mirror of
https://github.com/EpicEricEE/ShopChest.git
synced 2025-02-17 21:11:53 +01:00
Implement shop interaction
Product string of shop info message is still WIP
This commit is contained in:
parent
52d3833961
commit
1e4ba02e72
@ -0,0 +1,101 @@
|
||||
package de.epiceric.shopchest.api.event;
|
||||
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
import de.epiceric.shopchest.api.shop.Shop;
|
||||
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.EventPriority;
|
||||
|
||||
/**
|
||||
* Called when a player buys or sells something from or to a shop
|
||||
* <p>
|
||||
* The transaction takes place with {@link EventPriority#HIGHEST}.
|
||||
* If the transaction fails, this should be checked in a listener with
|
||||
* {@link EventPriority#MONITOR}.
|
||||
*
|
||||
* @since 1.13
|
||||
*/
|
||||
public class ShopUseEvent extends ShopEvent implements Cancellable {
|
||||
private Type type;
|
||||
private int amount;
|
||||
private double price;
|
||||
private boolean cancelled;
|
||||
|
||||
public ShopUseEvent(ShopPlayer player, Shop shop, Type type, int amount, double price) {
|
||||
super(player, shop);
|
||||
this.type = type;
|
||||
this.amount = amount;
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the shop use is a buy or a sell
|
||||
*
|
||||
* @return the type of shop use
|
||||
* @since 1.13
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount which might be modified by automatic item amount
|
||||
* calculation
|
||||
*
|
||||
* @return the amount
|
||||
* @since 1.13
|
||||
*/
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the amount of items the player will buy or sell
|
||||
* <p>
|
||||
* This might not be equal to the amount specified in {@link Shop#getProduct()}.
|
||||
*
|
||||
* @param amount the amount
|
||||
* @since 1.13
|
||||
*/
|
||||
public void setAmount(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the price the player and the vendor of the shop will pay or receive
|
||||
* <p>
|
||||
* This might not be equal to {@link Shop#getBuyPrice()} or
|
||||
* {@link Shop#getSellPrice()} due to automatic item amount calculation.
|
||||
*
|
||||
* @return the price
|
||||
* @since 1.13
|
||||
*/
|
||||
public double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the amount of money the player and the vendor of the shop will pay or
|
||||
* receive
|
||||
*
|
||||
* @param price the price
|
||||
* @since 1.13
|
||||
*/
|
||||
public void setPrice(double price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
cancelled = cancel;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
BUY, SELL;
|
||||
}
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
package de.epiceric.shopchest.listener;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.api.config.Config;
|
||||
import de.epiceric.shopchest.api.event.ShopCreateEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopPreCreateEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopSelectItemEvent;
|
||||
import de.epiceric.shopchest.api.flag.CreateFlag;
|
||||
import de.epiceric.shopchest.api.flag.SelectFlag;
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
import de.epiceric.shopchest.api.shop.Shop;
|
||||
import de.epiceric.shopchest.api.shop.ShopProduct;
|
||||
import de.epiceric.shopchest.shop.ShopProductImpl;
|
||||
import de.epiceric.shopchest.util.Logger;
|
||||
|
||||
public class ShopCreateListener implements Listener {
|
||||
private final ShopChest plugin;
|
||||
|
||||
public ShopCreateListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
private boolean isInt(double d) {
|
||||
return d % 1 == 0;
|
||||
}
|
||||
|
||||
private boolean validateItem(ShopPlayer player, Material type, double buyPrice, double sellPrice) {
|
||||
// Check if item is blacklisted
|
||||
if (Config.SHOP_CREATION_BLACKLIST.get().getList().contains(type)) {
|
||||
player.sendMessage("§cYou cannot create a shop with this item."); // TODO: i18n
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if minimum price is followed
|
||||
double minPrice = Config.SHOP_CREATION_MINIMUM_PRICES.get().getMap().getOrDefault(type, 0d);
|
||||
if (buyPrice > 0 && buyPrice < minPrice) {
|
||||
player.sendMessage("§cThe buy price must be higher than " + plugin.formatEconomy(minPrice) + "."); // TODO: i18n
|
||||
return false;
|
||||
} else if (sellPrice > 0 && sellPrice < minPrice) {
|
||||
player.sendMessage("§cThe sell price must be higher than " + plugin.formatEconomy(minPrice) + "."); // TODO: i18n
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if maximum price is followed
|
||||
double maxPrice = Config.SHOP_CREATION_MAXIMUM_PRICES.get().getMap().getOrDefault(type, Double.MAX_VALUE);
|
||||
if (buyPrice > 0 && buyPrice > maxPrice) {
|
||||
player.sendMessage("§cThe buy price must be lower than " + plugin.formatEconomy(maxPrice) + "."); // TODO: i18n
|
||||
return false;
|
||||
} else if (sellPrice > 0 && sellPrice > maxPrice) {
|
||||
player.sendMessage("§cThe sell price must be lower than " + plugin.formatEconomy(maxPrice) + "."); // TODO: i18n
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeCommand(ShopPreCreateEvent e) {
|
||||
ShopPlayer player = e.getPlayer();
|
||||
double buyPrice = e.getBuyPrice();
|
||||
double sellPrice = e.getSellPrice();
|
||||
|
||||
// Check permission admin shop
|
||||
if (e.isAdminShop() && !player.hasPermission("shopchest.create.admin")) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cYou don't have permission to create an admin shop."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: buy/sell and item based permission
|
||||
|
||||
// Check permission normal shop
|
||||
if (!e.isAdminShop() && !player.hasPermission("shopchest.create")) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cYou don't have permission to create a shop."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
// Check shop limit
|
||||
if (player.getShopAmount() >= player.getShopLimit()) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cYou don't have permission to create any more shops."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if either buying or selling is enabled
|
||||
if (buyPrice <= 0 && sellPrice <= 0) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cYou cannot have both prices set to zero."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if prices are integers
|
||||
boolean allowDecimals = Config.SHOP_CREATION_ALLOW_DECIMAL_PRICES.get();
|
||||
if (!allowDecimals && (!isInt(buyPrice) || !isInt(buyPrice))) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cThe prices must not contain decimals."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if buy price is higher than sell price
|
||||
boolean buyHigherSell = Config.FEATURES_VENDOR_MONEY_PROTECTION.get();
|
||||
if (buyHigherSell && buyPrice > 0 && buyPrice < sellPrice) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cThe buy price must at least be as high as the sell price to prevent players from stealing your money."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.isItemSelected()) {
|
||||
// Check if item is in blacklist, and if minimum/maximum prices are followed
|
||||
Material type = e.getItemStack().getType();
|
||||
if (!validateItem(player, type, buyPrice, sellPrice)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onCommand(ShopPreCreateEvent e) {
|
||||
ShopPlayer player = e.getPlayer();
|
||||
|
||||
if (!e.isItemSelected()) {
|
||||
if (!(player.getFlag().orElse(null) instanceof SelectFlag)) {
|
||||
// Set flag only if player doesn't already have SelectFlag
|
||||
SelectFlag.Type type = e.isAdminShop() ? SelectFlag.Type.ADMIN : SelectFlag.Type.NORMAL;
|
||||
SelectFlag flag = new SelectFlag(e.getAmount(),
|
||||
e.getBuyPrice(), e.getSellPrice(), type,
|
||||
player.getBukkitPlayer().getGameMode());
|
||||
|
||||
player.setFlag(flag);
|
||||
player.getBukkitPlayer().setGameMode(GameMode.CREATIVE);
|
||||
player.sendMessage("§aOpen your inventory and select the item you want to sell or buy."); // TODO: 18n
|
||||
}
|
||||
} else {
|
||||
ShopProduct product = new ShopProductImpl(e.getItemStack(), e.getAmount());
|
||||
player.setFlag(new CreateFlag(plugin, product, e.getBuyPrice(), e.getSellPrice(), e.isAdminShop()));
|
||||
player.sendMessage("§aClick a chest within 15 seconds to create a shop."); // TODO: 18n
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeSelect(ShopSelectItemEvent e) {
|
||||
if (!validateItem(e.getPlayer(), e.getItem().getType(), e.getBuyPrice(), e.getSellPrice())) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onSelect(ShopSelectItemEvent e) {
|
||||
ShopProduct product = new ShopProductImpl(e.getItem(), e.getAmount());
|
||||
ShopPlayer player = e.getPlayer();
|
||||
|
||||
if (!e.isEditingShop()) {
|
||||
player.setFlag(new CreateFlag(plugin, product, e.getBuyPrice(), e.getSellPrice(), e.isAdminShop()));
|
||||
player.sendMessage("§aItem has been selected: §e{0}", product.getLocalizedName()); // TODO: 18n
|
||||
player.sendMessage("§aClick a chest within 15 seconds to create a shop."); // TODO: 18n
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onAction(ShopCreateEvent e) {
|
||||
if (e.isCancelled() && !e.getPlayer().hasPermission("shopchest.create.protected")) {
|
||||
e.getPlayer().sendMessage("§cYou don't have permission to create a shop here."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
Shop shop = e.getShop();
|
||||
if (shop.isAdminShop()) {
|
||||
plugin.getShopManager()
|
||||
.addAdminShop(shop.getProduct(), shop.getLocation(), shop.getBuyPrice(), shop.getSellPrice())
|
||||
.thenAccept(newShop -> e.getPlayer().sendMessage("§aAdmin shop has been added with ID {0}.", newShop.getId())) // TODO: i18n
|
||||
.exceptionally(ex -> {
|
||||
Logger.severe("Failed to add admin shop");
|
||||
Logger.severe(ex);
|
||||
e.getPlayer().sendMessage("§cFailed to add admin shop: {0}", ex.getMessage()); // TODO: i18n
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
plugin.getShopManager()
|
||||
.addShop(shop.getVendor().get(), shop.getProduct(), shop.getLocation(), shop.getBuyPrice(), shop.getSellPrice())
|
||||
.thenAccept(newShop -> e.getPlayer().sendMessage("§aShop has been added with ID {0}.", newShop.getId())) // TODO: i18n
|
||||
.exceptionally(ex -> {
|
||||
Logger.severe("Failed to add shop");
|
||||
Logger.severe(ex);
|
||||
e.getPlayer().sendMessage("§cFailed to add shop: {0}", ex.getMessage()); // TODO: i18n
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
package de.epiceric.shopchest.listener;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import de.epiceric.shopchest.ShopChestImpl;
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.api.config.Config;
|
||||
import de.epiceric.shopchest.api.event.ShopEditEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopPreEditEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopSelectItemEvent;
|
||||
import de.epiceric.shopchest.api.flag.EditFlag;
|
||||
import de.epiceric.shopchest.api.flag.SelectFlag;
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
import de.epiceric.shopchest.api.shop.Shop;
|
||||
import de.epiceric.shopchest.api.shop.ShopProduct;
|
||||
import de.epiceric.shopchest.shop.ShopImpl;
|
||||
import de.epiceric.shopchest.shop.ShopProductImpl;
|
||||
import de.epiceric.shopchest.util.Logger;
|
||||
|
||||
public class ShopEditListener implements Listener {
|
||||
private final ShopChest plugin;
|
||||
|
||||
public ShopEditListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
private boolean isInt(double d) {
|
||||
return d % 1 == 0;
|
||||
}
|
||||
|
||||
private boolean validateItem(ShopPlayer player, Material type, double buyPrice, double sellPrice) {
|
||||
// Check if item is blacklisted
|
||||
if (Config.SHOP_CREATION_BLACKLIST.get().getList().contains(type)) {
|
||||
player.sendMessage("§cYou cannot create a shop with this item."); // TODO: i18n
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if minimum price is followed
|
||||
double minPrice = Config.SHOP_CREATION_MINIMUM_PRICES.get().getMap().getOrDefault(type, 0d);
|
||||
if (buyPrice > 0 && buyPrice < minPrice) {
|
||||
player.sendMessage("§cThe buy price must be higher than " + plugin.formatEconomy(minPrice) + "."); // TODO: i18n
|
||||
return false;
|
||||
} else if (sellPrice > 0 && sellPrice < minPrice) {
|
||||
player.sendMessage("§cThe sell price must be higher than " + plugin.formatEconomy(minPrice) + "."); // TODO: i18n
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if maximum price is followed
|
||||
double maxPrice = Config.SHOP_CREATION_MAXIMUM_PRICES.get().getMap().getOrDefault(type, Double.MAX_VALUE);
|
||||
if (buyPrice > 0 && buyPrice > maxPrice) {
|
||||
player.sendMessage("§cThe buy price must be lower than " + plugin.formatEconomy(maxPrice) + "."); // TODO: i18n
|
||||
return false;
|
||||
} else if (sellPrice > 0 && sellPrice > maxPrice) {
|
||||
player.sendMessage("§cThe sell price must be lower than " + plugin.formatEconomy(maxPrice) + "."); // TODO: i18n
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeCommand(ShopPreEditEvent e) {
|
||||
ShopPlayer player = e.getPlayer();
|
||||
double buyPrice = e.getBuyPrice();
|
||||
double sellPrice = e.getSellPrice();
|
||||
|
||||
// Check permission normal shop
|
||||
if (!player.hasPermission("shopchest.edit")) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cYou don't have permission to edit a shop."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: buy/sell and item based permission
|
||||
|
||||
if (e.hasBuyPrice() && e.hasSellPrice()) {
|
||||
// Check if either buying or selling is enabled
|
||||
if (e.getBuyPrice() == 0 && e.getSellPrice() == 0) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cYou cannot have both prices set to zero."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if buy price is higher than sell price
|
||||
boolean buyHigherSell = Config.FEATURES_VENDOR_MONEY_PROTECTION.get();
|
||||
if (buyHigherSell && e.getBuyPrice() > 0 && e.getBuyPrice() < e.getSellPrice()) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cThe buy price must at least be as high as the sell price to prevent players from stealing your money."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if prices are integers
|
||||
if (!Config.SHOP_CREATION_ALLOW_DECIMAL_PRICES.get()) {
|
||||
boolean isBuyPriceInt = e.hasBuyPrice() && isInt(e.getBuyPrice());
|
||||
boolean isSellPriceInt = e.hasSellPrice() && isInt(e.getSellPrice());
|
||||
if (!isBuyPriceInt || !isSellPriceInt) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cThe prices must not contain decimals."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.hasItemStack()) {
|
||||
// Check if item is in blacklist, and if minimum/maximum prices are followed
|
||||
Material type = e.getItemStack().getType();
|
||||
if (!validateItem(player, type, buyPrice, sellPrice)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
public void onCommand(ShopPreEditEvent e) {
|
||||
ShopPlayer player = e.getPlayer();
|
||||
|
||||
if (!e.hasItemStack() && e.willEditItem()) {
|
||||
if (!(player.getFlag().orElse(null) instanceof SelectFlag)) {
|
||||
// Set flag only if player doesn't already have SelectFlag
|
||||
SelectFlag flag = new SelectFlag(e.getAmount(),
|
||||
e.getBuyPrice(), e.getSellPrice(), SelectFlag.Type.EDIT,
|
||||
player.getBukkitPlayer().getGameMode());
|
||||
|
||||
player.setFlag(flag);
|
||||
player.getBukkitPlayer().setGameMode(GameMode.CREATIVE);
|
||||
player.sendMessage("§aOpen your inventory and select the item you want to sell or buy."); // TODO: 18n
|
||||
}
|
||||
} else {
|
||||
player.setFlag(new EditFlag(plugin, e.getItemStack(), e.getAmount(), e.getBuyPrice(), e.getSellPrice()));
|
||||
player.sendMessage("§aClick a chest within 15 seconds to make the edit."); // TODO: 18n
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeSelect(ShopSelectItemEvent e) {
|
||||
if (!validateItem(e.getPlayer(), e.getItem().getType(), e.getBuyPrice(), e.getSellPrice())) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onSelect(ShopSelectItemEvent e) {
|
||||
ShopProduct product = new ShopProductImpl(e.getItem(), e.getAmount());
|
||||
ShopPlayer player = e.getPlayer();
|
||||
|
||||
if (e.isEditingShop()) {
|
||||
player.setFlag(new EditFlag(plugin, e.getItem(), e.getAmount(), e.getBuyPrice(), e.getSellPrice()));
|
||||
player.sendMessage("§aItem has been selected: §e{0}", product.getLocalizedName()); // TODO: 18n
|
||||
player.sendMessage("§aClick a chest within 15 seconds to make the edit."); // TODO: 18n
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeAction(ShopEditEvent e) {
|
||||
Shop shop = e.getShop();
|
||||
ShopPlayer player = e.getPlayer();
|
||||
|
||||
// Check if either buying or selling is enabled
|
||||
if (e.getBuyPrice() == 0 && e.getSellPrice() == 0) {
|
||||
player.sendMessage("§cYou cannot have both prices set to zero."); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if buy price is higher than sell price
|
||||
boolean buyHigherSell = Config.FEATURES_VENDOR_MONEY_PROTECTION.get();
|
||||
if (buyHigherSell && e.getBuyPrice() > 0 && e.getBuyPrice() < e.getSellPrice()) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cThe buy price must at least be as high as the sell price to prevent players from stealing your money."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
// Check permissions
|
||||
if (shop.isAdminShop() && !player.hasPermission("shopchest.edit.admin")) {
|
||||
player.sendMessage("§cYou don't have permission to edit an admin shop."); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.isVendor(shop) && !player.hasPermission("shopchest.edit.other")) {
|
||||
player.sendMessage("§cYou don't have permission to edit this shop."); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onAction(ShopEditEvent e) {
|
||||
ShopImpl shop = (ShopImpl) e.getShop();
|
||||
shop.setBuyPrice(e.getBuyPrice());
|
||||
shop.setSellPrice(e.getSellPrice());
|
||||
shop.setProduct(new ShopProductImpl(e.getItemStack(), e.getAmount()));
|
||||
|
||||
((ShopChestImpl) plugin).getDatabase()
|
||||
.updateShop(shop)
|
||||
.thenRun(() -> e.getPlayer().sendMessage("§aShop has been edited.")) // TODO: i18n
|
||||
.exceptionally(ex -> {
|
||||
Logger.severe("Failed to save shop edit");
|
||||
Logger.severe(ex);
|
||||
e.getPlayer().sendMessage("§cFailed to save edit: {0}", ex.getMessage());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package de.epiceric.shopchest.listener;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.api.event.ShopExtendEvent;
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
import de.epiceric.shopchest.api.shop.Shop;
|
||||
import de.epiceric.shopchest.util.Logger;
|
||||
|
||||
public class ShopExtendListener implements Listener {
|
||||
private final ShopChest plugin;
|
||||
|
||||
private final Set<UUID> hasSentPermisionMessage = new HashSet<>();
|
||||
|
||||
public ShopExtendListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeAction(ShopExtendEvent e) {
|
||||
ShopPlayer player = e.getPlayer();
|
||||
UUID uuid = player.getBukkitPlayer().getUniqueId();
|
||||
if (e.getShop().isAdminShop()) {
|
||||
if (!player.hasPermission("shopchest.extend.admin")) {
|
||||
player.sendMessage("§cYou don't have permission to extend admin shops."); // TODO: i18n
|
||||
hasSentPermisionMessage.add(uuid);
|
||||
e.setCancelled(true);
|
||||
}
|
||||
} else if (!player.isVendor(e.getShop())) {
|
||||
if (!player.hasPermission("shopchest.extend.other")) {
|
||||
player.sendMessage("§cYou don't have permission to extend this shop."); // TODO: i18n
|
||||
hasSentPermisionMessage.add(uuid);
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onAction(ShopExtendEvent e) {
|
||||
UUID uuid = e.getPlayer().getBukkitPlayer().getUniqueId();
|
||||
if (e.isCancelled() && !e.getPlayer().hasPermission("shopchest.create.protected")) {
|
||||
if (!hasSentPermisionMessage.contains(uuid)) {
|
||||
e.getPlayer().sendMessage("§cYou don't have permission to extend this shop here."); // TODO: i18n
|
||||
}
|
||||
hasSentPermisionMessage.remove(uuid);
|
||||
return;
|
||||
}
|
||||
|
||||
Shop shop = e.getShop();
|
||||
plugin.getShopManager().removeShop(shop)
|
||||
.thenCompose((v) -> {
|
||||
if (shop.isAdminShop()) {
|
||||
return plugin.getShopManager().addAdminShop(shop.getProduct(),
|
||||
shop.getLocation(), shop.getBuyPrice(), shop.getSellPrice());
|
||||
} else {
|
||||
return plugin.getShopManager().addShop(shop.getVendor().get(), shop.getProduct(),
|
||||
shop.getLocation(), shop.getBuyPrice(), shop.getSellPrice());
|
||||
}
|
||||
})
|
||||
.exceptionally(ex -> {
|
||||
Logger.severe("Failed to extend shop");
|
||||
Logger.severe(ex);
|
||||
e.getPlayer().sendMessage("§cFailed to extend shop: {0}", ex.getMessage());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package de.epiceric.shopchest.listener;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.api.event.ShopInfoEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopPreInfoEvent;
|
||||
import de.epiceric.shopchest.api.exceptions.ChestNotFoundException;
|
||||
import de.epiceric.shopchest.api.flag.InfoFlag;
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
import de.epiceric.shopchest.api.shop.Shop;
|
||||
import de.epiceric.shopchest.api.shop.ShopProduct;
|
||||
import de.epiceric.shopchest.util.ItemUtil;
|
||||
|
||||
public class ShopInfoListener implements Listener {
|
||||
private final ShopChest plugin;
|
||||
|
||||
public ShopInfoListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
// TODO: Move to nms modules or get rid of nms references
|
||||
/* private BaseComponent[] getProductMessage(ShopProduct product) {
|
||||
try {
|
||||
TextComponent title = new TextComponent("Product: ");
|
||||
title.setColor(ChatColor.GOLD);
|
||||
|
||||
TextComponent amount = new TextComponent(product.getAmount() + " x ");
|
||||
amount.setColor(ChatColor.WHITE);
|
||||
|
||||
NBTTagCompound nbt = CraftItemStack.asNMSCopy(product.getItemStack()).save(new NBTTagCompound());
|
||||
String itemJson = new JsonPrimitive(nbt.toString()).toString();
|
||||
|
||||
TextComponent item = new TextComponent(product.getLocalizedName());
|
||||
item.setColor(ChatColor.WHITE);
|
||||
item.setUnderlined(true);
|
||||
item.setHoverEvent(new HoverEvent(Action.SHOW_ITEM, new BaseComponent[] { new TextComponent(itemJson) }));
|
||||
|
||||
return new BaseComponent[] { title, amount, item };
|
||||
} catch (Exception e) {
|
||||
Logger.severe("Failed to create JSON for item. Product preview will not be available.");
|
||||
Logger.severe(e);
|
||||
return TextComponent.fromLegacyText(MessageFormat.format("§6Product: §f{0} x {1}",
|
||||
product.getAmount(), product.getLocalizedName())); // TODO: i18n
|
||||
}
|
||||
} */
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onCommand(ShopPreInfoEvent e) {
|
||||
ShopPlayer player = e.getPlayer();
|
||||
player.setFlag(new InfoFlag(plugin));
|
||||
player.sendMessage("§aClick a shop within 15 seconds to retrieve information about it."); // TODO: 18n
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onAction(ShopInfoEvent e) {
|
||||
Shop shop = e.getShop();
|
||||
ShopProduct product = shop.getProduct();
|
||||
ShopPlayer player = e.getPlayer();
|
||||
|
||||
// TODO: i18n
|
||||
player.sendMessage("§e--------- §fShop Info §e-----------------------------");
|
||||
player.sendMessage("§7Hover over the underlined product for more details");
|
||||
player.sendMessage("§6Vendor: §f{0}", shop.getVendor().map(OfflinePlayer::getName).orElse("Admin"));
|
||||
// player.getBukkitPlayer().spigot().sendMessage(getProductMessage(product)); // TODO
|
||||
|
||||
if (!shop.isAdminShop()) {
|
||||
int inStock = 0;
|
||||
int freeSpace = 0;
|
||||
|
||||
try {
|
||||
for (ItemStack content : shop.getInventory().getStorageContents()) {
|
||||
if (ItemUtil.isEqual(content, product.getItemStack())) {
|
||||
freeSpace += content.getMaxStackSize() - content.getAmount();
|
||||
inStock += content.getAmount();
|
||||
} else if (content == null || content.getType() == Material.AIR) {
|
||||
freeSpace += product.getItemStack().getMaxStackSize();
|
||||
}
|
||||
}
|
||||
} catch (ChestNotFoundException ignored) {
|
||||
// Should not be possible since chest has to be clicked
|
||||
// for this event to be fired.
|
||||
}
|
||||
|
||||
// TODO: i18n
|
||||
if (shop.canPlayerBuy()) player.sendMessage("§6In stock: §f{0}", inStock);
|
||||
if (shop.canPlayerSell()) player.sendMessage("§6Free space: §f{0}", freeSpace);
|
||||
}
|
||||
|
||||
if (shop.canPlayerBuy()) player.sendMessage("§6Buy for: §f{0}", plugin.formatEconomy(shop.getBuyPrice()));
|
||||
if (shop.canPlayerSell()) player.sendMessage("§6Sell for: §f{0}", plugin.formatEconomy(shop.getSellPrice()));
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package de.epiceric.shopchest.listener;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.api.event.ShopOpenEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopPreOpenEvent;
|
||||
import de.epiceric.shopchest.api.flag.OpenFlag;
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
|
||||
public class ShopOpenListener implements Listener {
|
||||
private final ShopChest plugin;
|
||||
|
||||
public ShopOpenListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeCommand(ShopPreOpenEvent e) {
|
||||
if (!e.getPlayer().hasPermission("shopchest.open.other")) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage("§cYou don't have permission to open this shop."); // TODO: i18n
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onCommand(ShopPreOpenEvent e) {
|
||||
ShopPlayer player = e.getPlayer();
|
||||
player.setFlag(new OpenFlag(plugin));
|
||||
player.sendMessage("§aClick a shop within 15 seconds to open it."); // TODO: i18n
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeAction(ShopOpenEvent e) {
|
||||
if (e.getShop().isAdminShop()) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage("§cYou cannot open an admin shop."); // TODO: i18n
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package de.epiceric.shopchest.listener;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.api.event.ShopPreRemoveEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopRemoveAllEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopRemoveEvent;
|
||||
import de.epiceric.shopchest.api.flag.RemoveFlag;
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
import de.epiceric.shopchest.util.Logger;
|
||||
|
||||
public class ShopRemoveListener implements Listener {
|
||||
private final ShopChest plugin;
|
||||
|
||||
public ShopRemoveListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onCommand(ShopPreRemoveEvent e) {
|
||||
ShopPlayer player = e.getPlayer();
|
||||
player.setFlag(new RemoveFlag(plugin));
|
||||
player.sendMessage("§aClick a shop within 15 seconds to remove it."); // TODO: 18n
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeAction(ShopRemoveEvent e) {
|
||||
ShopPlayer player = e.getPlayer();
|
||||
if (e.getShop().isAdminShop()) {
|
||||
if (!player.hasPermission("shopchest.remove.admin")) {
|
||||
player.sendMessage("§cYou don't have permission to remove admin shops."); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
}
|
||||
} else if (!player.isVendor(e.getShop())) {
|
||||
if (!player.hasPermission("shopchest.remove.other")) {
|
||||
player.sendMessage("§cYou don't have permission to remove this shop."); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onAction(ShopRemoveEvent e) {
|
||||
plugin.getShopManager()
|
||||
.removeShop(e.getShop())
|
||||
.thenRun(() -> e.getPlayer().sendMessage("§aShop has been removed.")) // TODO: i18n
|
||||
.exceptionally(ex -> {
|
||||
Logger.severe("Failed to remove shop");
|
||||
Logger.severe(ex);
|
||||
e.getPlayer().sendMessage("§cFailed to remove shop: {0}", ex.getMessage()); // TODO: i18n
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeActionAll(ShopRemoveAllEvent e) {
|
||||
if (!e.getSender().hasPermission("shopchest.remove.all")) {
|
||||
e.setCancelled(true);
|
||||
e.getSender().sendMessage("§cYou don't have permission to remove those shops."); // TODO: i18n
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onActionAll(ShopRemoveAllEvent e) {
|
||||
CompletableFuture<?>[] futures = e.getShops().stream()
|
||||
.map(shop -> plugin.getShopManager().removeShop(shop))
|
||||
.toArray(CompletableFuture[]::new);
|
||||
|
||||
CompletableFuture.allOf(futures)
|
||||
.thenRun(() -> {
|
||||
int amount = e.getShops().size();
|
||||
String shops = amount == 1 ? "shop" : "shops";
|
||||
|
||||
e.getSender().sendMessage(MessageFormat.format("§aYou have removed §e{0} {1} §aowned by §e{2}§a.", // TODO: i18n
|
||||
amount, shops, e.getVendor().getName()));
|
||||
})
|
||||
.exceptionally(ex -> {
|
||||
Logger.severe("Failed to remove all shops of {0}", e.getVendor().getName());
|
||||
Logger.severe(ex);
|
||||
e.getSender().sendMessage(MessageFormat.format("§cFailed to remove shops: {0}", ex.getMessage())); // TODO: i18n
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,250 @@
|
||||
package de.epiceric.shopchest.listener;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.epiceric.shopchest.ShopChestImpl;
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.api.config.Config;
|
||||
import de.epiceric.shopchest.api.event.ShopUseEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopUseEvent.Type;
|
||||
import de.epiceric.shopchest.api.exceptions.ChestNotFoundException;
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
import de.epiceric.shopchest.api.shop.Shop;
|
||||
import de.epiceric.shopchest.api.shop.ShopProduct;
|
||||
import de.epiceric.shopchest.util.ItemUtil;
|
||||
import de.epiceric.shopchest.util.Logger;
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import net.milkbowl.vault.economy.EconomyResponse;
|
||||
|
||||
public class ShopUseListener implements Listener {
|
||||
private static final class InventoryData {
|
||||
private final int amount;
|
||||
private final int freeSpace;
|
||||
|
||||
private InventoryData(int amount, int freeSpace) {
|
||||
this.amount = amount;
|
||||
this.freeSpace = freeSpace;
|
||||
}
|
||||
}
|
||||
|
||||
private final ShopChest plugin;
|
||||
|
||||
public ShopUseListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
private void sendVendorMessage(Optional<OfflinePlayer> vendor, String message, Object... args) {
|
||||
if (Config.FEATURES_VENDOR_MESSAGES.get()) {
|
||||
vendor.filter(OfflinePlayer::isOnline)
|
||||
.map(OfflinePlayer::getPlayer)
|
||||
.ifPresent(p -> p.sendMessage(MessageFormat.format(message, args)));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkShiftClick(Shop shop, Player player, ShopUseEvent e) {
|
||||
int amount = e.getAmount();
|
||||
double price = e.getPrice();
|
||||
|
||||
if (player.isSneaking()) {
|
||||
int newAmount = shop.getProduct().getItemStack().getMaxStackSize();
|
||||
double newPrice = price * newAmount / amount;
|
||||
if (!Config.SHOP_CREATION_ALLOW_DECIMAL_PRICES.get()) {
|
||||
newPrice = e.getType() == Type.BUY ? Math.ceil(newPrice) : Math.floor(newPrice);
|
||||
}
|
||||
e.setPrice(newPrice);
|
||||
e.setAmount(newAmount);
|
||||
}
|
||||
}
|
||||
|
||||
private InventoryData getInventoryData(Inventory inventory, ItemStack itemStack) {
|
||||
int amount = 0;
|
||||
int freeSpace = 0;
|
||||
for (ItemStack content : inventory.getStorageContents()) {
|
||||
if (ItemUtil.isEqual(content, itemStack)) {
|
||||
amount += content.getAmount();
|
||||
freeSpace += content.getMaxStackSize() - content.getAmount();
|
||||
} else if (content == null || content.getType() == Material.AIR) {
|
||||
freeSpace += itemStack.getMaxStackSize();;
|
||||
}
|
||||
}
|
||||
return new InventoryData(amount, freeSpace);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void beforeAction(ShopUseEvent e) {
|
||||
Shop shop = e.getShop();
|
||||
ShopProduct product = shop.getProduct();
|
||||
ShopPlayer player = e.getPlayer();
|
||||
Player bukkitPlayer = player.getBukkitPlayer();
|
||||
Economy economy = ((ShopChestImpl) plugin).getEconomy();
|
||||
|
||||
if (!player.hasPermission("shopchest.use")) {
|
||||
player.sendMessage("§cYou don't have permission to use a shop.");
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryData playerData = getInventoryData(bukkitPlayer.getInventory(), product.getItemStack());
|
||||
InventoryData chestData;
|
||||
try {
|
||||
chestData = getInventoryData(shop.getInventory(), product.getItemStack());
|
||||
} catch (ChestNotFoundException ex) {
|
||||
Logger.severe("A non-existent chest has been clicked?!");
|
||||
Logger.severe(ex);
|
||||
player.sendMessage("§cThe shop chest you clicked does not seem to exist"); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
checkShiftClick(shop, bukkitPlayer, e);
|
||||
|
||||
// TODO: auto adjust item amount
|
||||
|
||||
// Check money, space and available items
|
||||
if (e.getType() == Type.BUY) {
|
||||
if (playerData.freeSpace < e.getAmount()) {
|
||||
player.sendMessage("§cYou don't have enough space in your inventory."); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (!economy.has(bukkitPlayer, shop.getWorld().getName(), e.getPrice())) {
|
||||
player.sendMessage("§cYou don't have enough money."); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (!shop.isAdminShop()) {
|
||||
if (chestData.amount < e.getAmount()) {
|
||||
player.sendMessage("§cThis shop is out of items to sell."); // TODO: i18n
|
||||
sendVendorMessage(shop.getVendor(), "§cYour shop selling §e{0} x {1} §cis out of stick.", // TODO: i18n
|
||||
product.getAmount(), product.getLocalizedName());
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (e.getType() == Type.SELL) {
|
||||
if (playerData.amount < e.getAmount()) {
|
||||
player.sendMessage("§cYou don't have enough items to sell."); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (!shop.isAdminShop()) {
|
||||
if (!economy.has(shop.getVendor().get(), shop.getWorld().getName(), e.getPrice())) {
|
||||
player.sendMessage("§cThe vendor of this shop doesn't have enough money."); // TODO: i18n
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (chestData.freeSpace < e.getAmount()) {
|
||||
player.sendMessage("§cThis shop doesn't have enough space for your items."); // TODO: i18n
|
||||
sendVendorMessage(shop.getVendor(), "§cYour shop buying §e{0} x {1} §cis full.", // TODO: i18n
|
||||
product.getAmount(), product.getLocalizedName());
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPrepareAction(ShopUseEvent e) {
|
||||
if (e.isCancelled() && !e.getPlayer().hasPermission("shopchest.use.protected")) {
|
||||
e.getPlayer().sendMessage("§cYou don't have permission to use this shop.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Money transaction in highest priority
|
||||
Shop shop = e.getShop();
|
||||
Economy economy = ((ShopChestImpl) plugin).getEconomy();
|
||||
Player bukkitPlayer = e.getPlayer().getBukkitPlayer();
|
||||
String worldName = e.getShop().getWorld().getName();
|
||||
|
||||
if (e.getType() == Type.BUY) {
|
||||
EconomyResponse rPlayer = economy.withdrawPlayer(bukkitPlayer, worldName, e.getPrice());
|
||||
if (!rPlayer.transactionSuccess()) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage("§cFailed to withdraw money: {0}", rPlayer.errorMessage); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
shop.getVendor().ifPresent(vendor -> {
|
||||
EconomyResponse rVendor = economy.depositPlayer(vendor, worldName, e.getPrice());
|
||||
if (!rVendor.transactionSuccess()) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage("§cFailed to deposit money to vendor: {0}", rVendor.errorMessage); // TODO: i18n
|
||||
|
||||
EconomyResponse rBack = economy.depositPlayer(bukkitPlayer, worldName, e.getPrice());
|
||||
if (!rBack.transactionSuccess()) {
|
||||
e.getPlayer().sendMessage("§cFailed to reverse your withdrawal: {0}", rBack.errorMessage); // TODO: i18n
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
} else if (e.getType() == Type.SELL) {
|
||||
EconomyResponse rPlayer = economy.depositPlayer(bukkitPlayer, worldName, e.getPrice());
|
||||
if (!rPlayer.transactionSuccess()) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage("§cFailed to deposit money: {0}", rPlayer.errorMessage); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
shop.getVendor().ifPresent(vendor -> {
|
||||
EconomyResponse rVendor = economy.withdrawPlayer(vendor, worldName, e.getPrice());
|
||||
if (!rVendor.transactionSuccess()) {
|
||||
e.setCancelled(true);
|
||||
e.getPlayer().sendMessage("§cFailed to withdraw money from vendor: {0}", rVendor.errorMessage); // TODO: i18n
|
||||
|
||||
EconomyResponse rBack = economy.withdrawPlayer(bukkitPlayer, worldName, e.getPrice());
|
||||
if (!rBack.transactionSuccess()) {
|
||||
e.getPlayer().sendMessage("§cFailed to reverse your deposit: {0}", rBack.errorMessage); // TODO: i18n
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onAction(ShopUseEvent e) {
|
||||
Shop shop = e.getShop();
|
||||
ShopPlayer player = e.getPlayer();
|
||||
ShopProduct product = shop.getProduct();
|
||||
Player bukkitPlayer = player.getBukkitPlayer();
|
||||
|
||||
try {
|
||||
if (e.getType() == Type.BUY) {
|
||||
for (int i = 0; i < e.getAmount(); i++) {
|
||||
bukkitPlayer.getInventory().addItem(product.getItemStack());
|
||||
if (!shop.isAdminShop()) {
|
||||
shop.getInventory().removeItem(product.getItemStack());
|
||||
}
|
||||
}
|
||||
|
||||
player.sendMessage("§aYou bought §e{0} x {1} §afor §e{2}.", e.getAmount(),
|
||||
product.getLocalizedName(), plugin.formatEconomy(e.getPrice()));
|
||||
} else {
|
||||
for (int i = 0; i < e.getAmount(); i++) {
|
||||
bukkitPlayer.getInventory().removeItem(product.getItemStack());
|
||||
if (!shop.isAdminShop()) {
|
||||
shop.getInventory().addItem(product.getItemStack());
|
||||
}
|
||||
}
|
||||
|
||||
player.sendMessage("§aYou sold §e{0} x {1} §afor §e{2}.", e.getAmount(),
|
||||
product.getLocalizedName(), plugin.formatEconomy(e.getPrice()));
|
||||
}
|
||||
} catch (ChestNotFoundException ex) {
|
||||
Logger.severe("A non-existent chest has been clicked?!");
|
||||
Logger.severe(ex);
|
||||
player.sendMessage("§cThe shop chest you clicked does not seem to exist"); // TODO: i18n
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
package de.epiceric.shopchest.listener.internal;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.block.Chest;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.api.config.Config;
|
||||
import de.epiceric.shopchest.api.event.ShopUseEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopCreateEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopEditEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopInfoEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopOpenEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopRemoveEvent;
|
||||
import de.epiceric.shopchest.api.event.ShopUseEvent.Type;
|
||||
import de.epiceric.shopchest.api.flag.CreateFlag;
|
||||
import de.epiceric.shopchest.api.flag.EditFlag;
|
||||
import de.epiceric.shopchest.api.flag.Flag;
|
||||
import de.epiceric.shopchest.api.flag.InfoFlag;
|
||||
import de.epiceric.shopchest.api.flag.OpenFlag;
|
||||
import de.epiceric.shopchest.api.flag.RemoveFlag;
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
import de.epiceric.shopchest.api.shop.Shop;
|
||||
import de.epiceric.shopchest.shop.ShopImpl;
|
||||
|
||||
public class ChestInteractListener implements Listener {
|
||||
private ShopChest plugin;
|
||||
|
||||
public ChestInteractListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
private void handleShopUse(Shop shop, ShopPlayer player, Type type, Cancellable e) {
|
||||
if (player.isVendor(shop)) {
|
||||
return; // vendors cannot use their own shops
|
||||
}
|
||||
|
||||
e.setCancelled(true);
|
||||
|
||||
if (player.getBukkitPlayer().getGameMode() == GameMode.CREATIVE) {
|
||||
player.sendMessage("§cYou cannot use a shop in creative mode."); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
if (Config.CORE_INVERT_MOUSE_BUTTONS.get()) {
|
||||
type = type == Type.BUY ? Type.SELL : Type.BUY;
|
||||
}
|
||||
|
||||
double price = type == Type.BUY ? shop.getBuyPrice() : shop.getSellPrice();
|
||||
if (price <= 0) {
|
||||
String typeStr = type == Type.BUY ? "buy" : "sell";
|
||||
player.sendMessage("§cYou cannot {0} at this shop.", typeStr); // TODO: i18n
|
||||
return;
|
||||
}
|
||||
|
||||
plugin.getServer().getPluginManager()
|
||||
.callEvent(new ShopUseEvent(player, shop, type, shop.getProduct().getAmount(), price));
|
||||
}
|
||||
|
||||
private void handleFlags(ShopPlayer player, Shop shop, Cancellable e) {
|
||||
if (!player.getFlag().isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Flag flag = player.getFlag().get();
|
||||
player.removeFlag();
|
||||
|
||||
if (flag instanceof InfoFlag) {
|
||||
plugin.getServer().getPluginManager().callEvent(new ShopInfoEvent(player, shop));
|
||||
e.setCancelled(true);
|
||||
} else if (flag instanceof RemoveFlag) {
|
||||
plugin.getServer().getPluginManager().callEvent(new ShopRemoveEvent(player, shop));
|
||||
e.setCancelled(true);
|
||||
} else if (flag instanceof OpenFlag) {
|
||||
ShopOpenEvent event = new ShopOpenEvent(player, shop);
|
||||
plugin.getServer().getPluginManager().callEvent(event);
|
||||
e.setCancelled(event.isCancelled());
|
||||
} else if (flag instanceof EditFlag) {
|
||||
EditFlag editFlag = (EditFlag) flag;
|
||||
plugin.getServer().getPluginManager().callEvent(new ShopEditEvent(player, shop, editFlag.getItemStack(),
|
||||
editFlag.getAmount(), editFlag.getBuyPrice(), editFlag.getSellPrice()));
|
||||
e.setCancelled(true);
|
||||
} else if (flag instanceof CreateFlag) {
|
||||
e.setCancelled(true);
|
||||
player.sendMessage("§cThis chest already is a shop."); // TODO: i18n
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||
public void onPlayerInteract(PlayerInteractEvent e) {
|
||||
if (e.getAction() != Action.RIGHT_CLICK_BLOCK && e.getAction() != Action.LEFT_CLICK_BLOCK) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.getHand() != EquipmentSlot.HAND) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(e.getClickedBlock().getState() instanceof Chest)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location location = e.getClickedBlock().getLocation();
|
||||
ShopPlayer player = plugin.wrapPlayer(e.getPlayer());
|
||||
Optional<Shop> shopOpt = plugin.getShopManager().getShop(location);
|
||||
|
||||
if (shopOpt.isPresent()) {
|
||||
Shop shop = shopOpt.get();
|
||||
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
|
||||
if (player.getFlag().isPresent()) {
|
||||
// handle flags
|
||||
handleFlags(player, shop, e);
|
||||
} else if (e.hasItem() && e.getItem().getType() == Config.CORE_SHOP_INFO_ITEM.get()) {
|
||||
// handle shop interaction item
|
||||
plugin.getServer().getPluginManager().callEvent(new ShopInfoEvent(player, shopOpt.get()));
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
} else {
|
||||
// handle buy
|
||||
handleShopUse(shop, player, Type.BUY, e);
|
||||
}
|
||||
} else {
|
||||
// handle sell
|
||||
handleShopUse(shop, player, Type.SELL, e);
|
||||
}
|
||||
} else {
|
||||
// handle create
|
||||
if (e.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
player.getFlag().filter(flag -> flag instanceof CreateFlag).ifPresent(f -> {
|
||||
e.setCancelled(true);
|
||||
CreateFlag flag = (CreateFlag) f;
|
||||
player.removeFlag();
|
||||
OfflinePlayer vendor = flag.isAdminShop() ? null : player.getBukkitPlayer();
|
||||
plugin.getServer().getPluginManager().callEvent(new ShopCreateEvent(player,
|
||||
new ShopImpl(vendor, flag.getProduct(), location, flag.getBuyPrice(), flag.getSellPrice()),
|
||||
Config.SHOP_CREATION_PRICE.get()));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package de.epiceric.shopchest.listener.internal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
|
||||
import de.epiceric.shopchest.ShopChestImpl;
|
||||
import de.epiceric.shopchest.ShopManagerImpl;
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.util.Logger;
|
||||
|
||||
public class ChunkLoadListener implements Listener {
|
||||
private ShopChest plugin;
|
||||
|
||||
private final Set<Chunk> newLoadedChunks = new HashSet<>();
|
||||
|
||||
public ChunkLoadListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkLoad(ChunkLoadEvent e) {
|
||||
if (!((ShopChestImpl) plugin).getDatabase().isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait 10 ticks after first event is triggered, so that multiple
|
||||
// chunk loads can be handled at the same time without having to
|
||||
// send a database request for each chunk.
|
||||
|
||||
if (newLoadedChunks.isEmpty()) {
|
||||
plugin.getServer().getScheduler().runTaskLater(plugin, () -> {
|
||||
int chunkCount = newLoadedChunks.size();
|
||||
|
||||
((ShopManagerImpl) plugin.getShopManager())
|
||||
.loadShops(newLoadedChunks.toArray(new Chunk[chunkCount]))
|
||||
.exceptionally(ex -> {
|
||||
Logger.severe("Failed to load shops in newly loaded chunks");
|
||||
Logger.severe(ex);
|
||||
return null;
|
||||
});
|
||||
|
||||
newLoadedChunks.clear();
|
||||
}, 10L);
|
||||
}
|
||||
newLoadedChunks.add(e.getChunk());
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
package de.epiceric.shopchest.listener.internal;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockMultiPlaceEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.inventory.InventoryMoveItemEvent;
|
||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.api.event.ShopSelectItemEvent;
|
||||
import de.epiceric.shopchest.api.flag.SelectFlag;
|
||||
import de.epiceric.shopchest.api.player.ShopPlayer;
|
||||
|
||||
public class CreativeSelectListener implements Listener {
|
||||
private final ShopChest plugin;
|
||||
|
||||
public CreativeSelectListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onInventoryClick(InventoryClickEvent e) {
|
||||
if (!(e.getWhoClicked() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ShopPlayer player = plugin.wrapPlayer((Player) e.getWhoClicked());
|
||||
player.getFlag().filter(flag -> flag instanceof SelectFlag).ifPresent(f -> {
|
||||
e.setCancelled(true);
|
||||
|
||||
if (e.getCursor() == null || e.getCursor().getType() == Material.AIR) {
|
||||
return;
|
||||
}
|
||||
|
||||
SelectFlag flag = (SelectFlag) f;
|
||||
player.removeFlag();
|
||||
plugin.getServer().getScheduler().runTask(plugin, () -> player.getBukkitPlayer().closeInventory());
|
||||
|
||||
plugin.getServer().getPluginManager().callEvent(new ShopSelectItemEvent(player, e.getCursor(),
|
||||
flag.getAmount(), flag.getBuyPrice(), flag.getSellPrice(), flag.getType()));
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClose(InventoryCloseEvent e) {
|
||||
if (!(e.getPlayer() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ShopPlayer player = plugin.wrapPlayer((Player) e.getPlayer());
|
||||
if (hasSelectFlag(player)) {
|
||||
player.removeFlag();
|
||||
player.sendMessage("§cShop creation has been cancelled.");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
||||
// Remove flag to reset game mode if SelectFlag is assigned
|
||||
plugin.wrapPlayer(e.getPlayer()).removeFlag();
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onInventoryDrag(InventoryDragEvent e) {
|
||||
// Cancel any inventory drags if SelectFlag is assigned
|
||||
if (!(e.getWhoClicked() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ShopPlayer player = plugin.wrapPlayer((Player) e.getWhoClicked());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onInventoryMove(InventoryMoveItemEvent e) {
|
||||
// Cancel any inventory movement if SelectFlag is assigned
|
||||
if (!(e.getSource().getHolder() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ShopPlayer player = plugin.wrapPlayer((Player) e.getSource().getHolder());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onEntityPickup(EntityPickupItemEvent e) {
|
||||
// Cancel any item pickups if SelectFlag is assigned
|
||||
if (!(e.getEntity() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ShopPlayer player = plugin.wrapPlayer((Player) e.getEntity());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onBlockBreak(BlockBreakEvent e) {
|
||||
// Cancel any block breaks if SelectFlag is assigned
|
||||
ShopPlayer player = plugin.wrapPlayer(e.getPlayer());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onBlockPlace(BlockPlaceEvent e) {
|
||||
// Cancel any block places if SelectFlag is assigned
|
||||
ShopPlayer player = plugin.wrapPlayer(e.getPlayer());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onBlockMultiPlace(BlockMultiPlaceEvent e) {
|
||||
// Cancel any block places if SelectFlag is assigned
|
||||
ShopPlayer player = plugin.wrapPlayer(e.getPlayer());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerInteract(PlayerInteractEvent e) {
|
||||
// Cancel any interactions if SelectFlag is assigned
|
||||
ShopPlayer player = plugin.wrapPlayer(e.getPlayer());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent e) {
|
||||
// Cancel any entity interactions if SelectFlag is assigned
|
||||
ShopPlayer player = plugin.wrapPlayer(e.getPlayer());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerDamageEntity(EntityDamageByEntityEvent e) {
|
||||
// Cancel any entity damaging if SelectFlag is assigned
|
||||
if (!(e.getDamager() instanceof Player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ShopPlayer player = plugin.wrapPlayer((Player) e.getDamager());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPlayerMove(PlayerMoveEvent e) {
|
||||
// Cancel any player movement if SelectFlag is assigned
|
||||
ShopPlayer player = plugin.wrapPlayer(e.getPlayer());
|
||||
if (hasSelectFlag(player)) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasSelectFlag(ShopPlayer player) {
|
||||
return player.getFlag().filter(flag -> flag instanceof SelectFlag).isPresent();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package de.epiceric.shopchest.listener.internal;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import de.epiceric.shopchest.api.ShopChest;
|
||||
import de.epiceric.shopchest.player.ShopPlayerImpl;
|
||||
import de.epiceric.shopchest.shop.ShopImpl;
|
||||
|
||||
public class PlayerJoinQuitListener implements Listener {
|
||||
private final ShopChest plugin;
|
||||
|
||||
public PlayerJoinQuitListener(ShopChest plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent e) {
|
||||
// TODO: Make dynamic
|
||||
plugin.getShopManager().getShops(e.getPlayer().getWorld())
|
||||
.forEach(shop -> ((ShopImpl) shop).getHologram().showPlayer(e.getPlayer()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent e) {
|
||||
ShopPlayerImpl.unregister(e.getPlayer());
|
||||
}
|
||||
}
|
6
pom.xml
6
pom.xml
@ -64,9 +64,9 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.15.2-R0.1-SNAPSHOT</version>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.16.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
Loading…
Reference in New Issue
Block a user