Refactor/rework

This commit is contained in:
Len 2022-08-22 00:21:36 +02:00
parent 658837814a
commit 3aa8414c5b
17 changed files with 885 additions and 12 deletions

3
.gitignore vendored
View File

@ -47,5 +47,6 @@ out/
*~ *~
!gradle/wrapper/gradle-wrapper.jar !gradle/wrapper/gradle-wrapper.jar
/run/ /run1/
/lib/ /lib/
/run/

View File

@ -82,10 +82,23 @@ bukkit {
authors = listOf("destro174") authors = listOf("destro174")
depend = listOf("Vault") depend = listOf("Vault")
commands {
register("playershop") {
description = "This is a test command!"
aliases = listOf("shop")
permission = "playershops.command.playershop"
}
}
permissions { permissions {
register("playershops.admin") { register("playershops.admin") {
description = "Admin permission for the ${rootProject.name} plugin." description = "Admin permission for the ${rootProject.name} plugin."
default = BukkitPluginDescription.Permission.Default.FALSE default = BukkitPluginDescription.Permission.Default.FALSE
children = listOf(
"playershops.shop.create",
"playershops.shop.break.other",
"playershops.shop.use"
)
} }
register("playershops.shoplimit") { register("playershops.shoplimit") {
description = "Base permission to allow per player shop limits." description = "Base permission to allow per player shop limits."
@ -102,6 +115,30 @@ bukkit {
register("playershops.shop.break.other") { register("playershops.shop.break.other") {
description = "Allows players to break other players shops." description = "Allows players to break other players shops."
default = BukkitPluginDescription.Permission.Default.FALSE default = BukkitPluginDescription.Permission.Default.FALSE
children = listOf(
"playershops.shop.break",
)
}
register("playershops.shop.use") {
description = "Allows players to use all playershops."
default = BukkitPluginDescription.Permission.Default.FALSE
children = listOf(
"playershops.shop.use.buy",
"playershops.shop.use.sell",
"playershops.shop.use.gamble"
)
}
register("playershops.shop.use.buy") {
description = "Allows players to use buying playershops."
default = BukkitPluginDescription.Permission.Default.FALSE
}
register("playershops.shop.use.sell") {
description = "Allows players to use selling playershops."
default = BukkitPluginDescription.Permission.Default.FALSE
}
register("playershops.shop.use.gamble") {
description = "Allows players to use gamble playershops."
default = BukkitPluginDescription.Permission.Default.FALSE
} }
} }
} }

View File

@ -9,6 +9,7 @@ import com.alttd.playershops.handler.ShopHandler;
import com.alttd.playershops.listener.BlockListener; import com.alttd.playershops.listener.BlockListener;
import com.alttd.playershops.listener.PlayerListener; import com.alttd.playershops.listener.PlayerListener;
import com.alttd.playershops.listener.ShopListener; import com.alttd.playershops.listener.ShopListener;
import com.alttd.playershops.listener.TransactionListener;
import com.alttd.playershops.shop.ShopType; import com.alttd.playershops.shop.ShopType;
import com.alttd.playershops.storage.DatabaseManager; import com.alttd.playershops.storage.DatabaseManager;
import lombok.Getter; import lombok.Getter;
@ -31,6 +32,7 @@ public class PlayerShops extends JavaPlugin {
private ShopListener shopListener; private ShopListener shopListener;
private PlayerListener playerListener; private PlayerListener playerListener;
private BlockListener blockListener; private BlockListener blockListener;
private TransactionListener transactionListener;
public void onEnable() { public void onEnable() {
instance = this; instance = this;
@ -77,12 +79,14 @@ public class PlayerShops extends JavaPlugin {
shopListener = new ShopListener(this); shopListener = new ShopListener(this);
playerListener = new PlayerListener(this); playerListener = new PlayerListener(this);
blockListener = new BlockListener(this); blockListener = new BlockListener(this);
transactionListener = new TransactionListener(this);
} }
private void unRegisterListeners() { private void unRegisterListeners() {
shopListener.unregister(); shopListener.unregister();
playerListener.unregister(); playerListener.unregister();
blockListener.unregister(); blockListener.unregister();
transactionListener.unregister();
} }
private void registerCommands() { private void registerCommands() {

View File

@ -0,0 +1,47 @@
package com.alttd.playershops.commands;
import com.alttd.playershops.gui.ShopManagementGui;
import com.alttd.playershops.shop.PlayerShop;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// expose brig in Galaxy?
public class ShopCommand implements CommandExecutor, TabCompleter {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) return true;
if (args.length == 0) {
return true;
}
switch (args[0].toLowerCase()) {
case "reload":
break;
case "open":
ShopManagementGui gui = new ShopManagementGui(player.getUniqueId(), new PlayerShop(player.getLocation(), player.getLocation(), player));
gui.open();
break;
default:
sender.sendMessage("invalid command useage");
break;
}
return false;
}
@Override
public List<String> onTabComplete(CommandSender sender, Command cmd, String label, String[] args) {
if (args.length == 1) {
return Stream.of("reload", "open")
.filter(arg -> arg.startsWith(args[0].toLowerCase()))
.collect(Collectors.toList());
}
return null;
}
}

View File

@ -0,0 +1,65 @@
package com.alttd.playershops.config;
import io.leangen.geantyref.TypeToken;
import org.spongepowered.configurate.serialize.SerializationException;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("unused")
public class GuiIconConfig {
private final String icon;
private final String configPath;
private final String defaultPath;
public GuiIconConfig(String icon) {
this.icon = icon;
this.configPath = "gui-icon." + this.icon + ".";
this.defaultPath = "gui-icon.divider.";
init();
}
static int version;
public void init() {
Config.config.readConfig(GuiIconConfig.class, this);
}
private static void set(String path, Object def) {
Config.config.set(path, def);
}
private String getString(String path, String def) {
set(defaultPath + path, def);
return Config.config.getNode(configPath + path).getString(
Config.config.getNode(defaultPath + path).getString(def));
}
private int getInt(String path, int def) {
set(defaultPath + path, def);
return Config.config.getNode(configPath + path).getInt(
Config.config.getNode(defaultPath + path).getInt(def));
}
private List<String> getStringList(String path, List<String> def) {
try {
set(defaultPath + path, def);
return Config.config.getNode(configPath + path).getList(TypeToken.get(String.class),
Config.config.getNode(defaultPath + path).getList(TypeToken.get(String.class), def));
} catch(SerializationException ignore) {}
return new ArrayList<>();
}
public int slot = 0;
public String displayName = "Default";
public String material = "dirt";
public List<String> lore = new ArrayList<>();
private void guiItems() {
slot = getInt("slot", slot);
material = getString("material", material);
displayName = getString("display-name", displayName);
lore = getStringList("lore", lore);
}
}

View File

@ -0,0 +1,116 @@
package com.alttd.playershops.gui;
import com.alttd.playershops.config.GuiIconConfig;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public abstract class AbstractGui implements InventoryHolder {
Inventory inventory;
protected final int INV_SIZE = 54;
int currentSlot;
UUID uuid;
int pageIndex;
AbstractGui(UUID uuid) {
this.uuid = uuid;
this.currentSlot = 0;
}
public void open() {
Player player = getPlayer();
if (player != null) {
player.openInventory(inventory);
}
}
boolean close() {
Player player = getPlayer();
if (player != null) {
player.closeInventory();
return true;
}
return false;
}
void scrollPageNext() {
ItemStack nextPageIcon = inventory.getItem(GuiIcon.MENUBAR_NEXT_PAGE.getSlot());
if (nextPageIcon != null && nextPageIcon.equals(getNextPageIcon())) {
inventory.setItem(GuiIcon.MENUBAR_NEXT_PAGE.getSlot(), getPrevPageIcon());
++pageIndex;
initInvContents();
}
}
void scrollPagePrev() {
ItemStack prevPageIcon = inventory.getItem(GuiIcon.MENUBAR_PREV_PAGE.getSlot());
if (prevPageIcon != null && prevPageIcon.equals(getPrevPageIcon())) {
inventory.setItem(GuiIcon.MENUBAR_PREV_PAGE.getSlot(), getNextPageIcon());
--pageIndex;
if (pageIndex == 0) {
inventory.setItem(GuiIcon.MENUBAR_PREV_PAGE.getSlot(), null);
}
initInvContents();
}
}
protected boolean addItem(ItemStack icon) {
if (currentSlot == inventory.getSize())
return false;
inventory.setItem(currentSlot, icon);
currentSlot++;
return true;
}
void initInvContents() {
clearInvBody();
currentSlot = 0;
}
protected void clearInvBody() {
for (int i = 0; i < inventory.getSize() - 9; ++i) {
inventory.setItem(i, null);
}
}
void makeMenuBar() {
for (int i = inventory.getSize() - 9; i < inventory.getSize(); ++i) {
inventory.setItem(i, getDivider());
}
}
Player getPlayer() {
return Bukkit.getPlayer(uuid);
}
@NotNull
@Override
public Inventory getInventory() {
return inventory;
}
ItemStack getPrevPageIcon() {
return GuiIcon.MENUBAR_PREV_PAGE.getItemStack();
}
ItemStack getNextPageIcon() {
return GuiIcon.MENUBAR_NEXT_PAGE.getItemStack();
}
ItemStack getExitIcon() {
return null;
}
ItemStack getDivider() {
return GuiIcon.DIVIDER.getItemStack();
}
}

View File

@ -0,0 +1,76 @@
package com.alttd.playershops.gui;
import com.alttd.playershops.config.GuiIconConfig;
import com.alttd.playershops.config.ShopTypeConfig;
import com.alttd.playershops.utils.Util;
import lombok.Getter;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.List;
public enum GuiIcon {
DIVIDER,
MENUBAR_BACK,
MENUBAR_EXIT,
MENUBAR_SEARCH,
MENUBAR_PREV_PAGE,
MENUBAR_NEXT_PAGE,
MANAGE_SHOP,
MANAGE_SHOP_BALANCE_ADD,
MANAGE_SHOP_BALANCE_REMOVE,
MANAGE_SHOP_SALES,
MANAGE_SHOP_ITEM,
MANAGE_SHOP_TYPE,
HOME_LIST_OWN_SHOPS,
HOME_LIST_PLAYERS,
HOME_SETTINGS,
LIST_SHOP,
LIST_PLAYER,
LIST_PLAYER_ADMIN;
@Getter
private final int slot;
@Getter
private final ItemStack itemStack;
GuiIcon() {
GuiIconConfig config = new GuiIconConfig(this.toString());
this.slot = config.slot;
this.itemStack = createItem(config.material, config.displayName, config.lore);
}
private ItemStack createItem(String materialString, String displayName, List<String> itemlore) {
Material material = Material.getMaterial(materialString);
if (material == null)
return null;
ItemStack item = new ItemStack(material);
ItemMeta itemMeta = item.getItemMeta();
itemMeta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
itemMeta.displayName(format(displayName));
List<Component> lore = new ArrayList<>();
for (String line : itemlore) {
lore.add(format(line));
}
itemMeta.lore(lore);
item.setItemMeta(itemMeta);
return item;
}
private Component format(String s) {
return Util.parseMiniMessage(s, null);
}
@Override
public String toString() {
return name().toLowerCase();
}
}

View File

@ -0,0 +1,44 @@
package com.alttd.playershops.gui;
import com.alttd.playershops.shop.PlayerShop;
import com.alttd.playershops.utils.Util;
import org.bukkit.Bukkit;
import java.util.UUID;
public class ShopManagementGui extends AbstractGui {
PlayerShop shop;
public ShopManagementGui(UUID uuid, PlayerShop shop) {
super(uuid);
this.inventory = Bukkit.createInventory(this, INV_SIZE, Util.parseMiniMessage("Config.gui.management-title", null));
this.shop = shop;
initInvContents();
}
@Override
void initInvContents() {
// super.initInvContents();
makeMenuBar();
for (int i = 0; i < inventory.getSize() - 9; ++i) {
inventory.setItem(i, getDivider());
}
inventory.setItem(GuiIcon.MANAGE_SHOP.getSlot(), GuiIcon.MANAGE_SHOP.getItemStack());
inventory.setItem(GuiIcon.MANAGE_SHOP_BALANCE_ADD.getSlot(), GuiIcon.MANAGE_SHOP_BALANCE_ADD.getItemStack());
inventory.setItem(GuiIcon.MANAGE_SHOP_BALANCE_REMOVE.getSlot(), GuiIcon.MANAGE_SHOP_BALANCE_REMOVE.getItemStack());
inventory.setItem(GuiIcon.MANAGE_SHOP_SALES.getSlot(), GuiIcon.MANAGE_SHOP_SALES.getItemStack());
inventory.setItem(GuiIcon.MANAGE_SHOP_ITEM.getSlot(), GuiIcon.MANAGE_SHOP_ITEM.getItemStack());
inventory.setItem(GuiIcon.MANAGE_SHOP_TYPE.getSlot(), GuiIcon.MANAGE_SHOP_TYPE.getItemStack());
}
@Override
void makeMenuBar() {
super.makeMenuBar();
inventory.setItem(GuiIcon.MENUBAR_BACK.getSlot(), GuiIcon.MENUBAR_BACK.getItemStack());
inventory.setItem(GuiIcon.MENUBAR_PREV_PAGE.getSlot(), GuiIcon.MENUBAR_PREV_PAGE.getItemStack());
// inventory.setItem(49, new ItemStack(Material.NETHER_STAR));
inventory.setItem(GuiIcon.MENUBAR_NEXT_PAGE.getSlot(), GuiIcon.MENUBAR_NEXT_PAGE.getItemStack());
}
}

View File

@ -22,12 +22,14 @@ public class ShopHandler {
private final Object2IntMap<UUID> shopBuildLimits; private final Object2IntMap<UUID> shopBuildLimits;
@Getter @Getter
private final Map<Location, PlayerShop> shopLocation; private final Map<Location, PlayerShop> shopLocation;
private final Map<Location, PlayerShop> shopSignLocation;
@Getter @Getter
private final ArrayList<Material> shopMaterials; private final ArrayList<Material> shopMaterials;
public ShopHandler(PlayerShops instance) { public ShopHandler(PlayerShops instance) {
plugin = instance; plugin = instance;
shopLocation = new ConcurrentHashMap<>(); shopLocation = new ConcurrentHashMap<>();
shopSignLocation = new ConcurrentHashMap<>();
shopBuildLimits = new Object2IntOpenHashMap<>(); shopBuildLimits = new Object2IntOpenHashMap<>();
shopBuildLimits.defaultReturnValue(Config.shopLimit); shopBuildLimits.defaultReturnValue(Config.shopLimit);
shopMaterials = new ArrayList<>(); // TODO move into parent method where materials are loaded in. shopMaterials = new ArrayList<>(); // TODO move into parent method where materials are loaded in.
@ -58,6 +60,7 @@ public class ShopHandler {
public void removeShops() { public void removeShops() {
shopLocation.clear(); shopLocation.clear();
shopSignLocation.clear();
} }
public boolean isShopMaterial(Block block) { public boolean isShopMaterial(Block block) {
@ -77,18 +80,22 @@ public class ShopHandler {
} }
public PlayerShop getShopBySignLocation(Location signLocation) { public PlayerShop getShopBySignLocation(Location signLocation) {
for (PlayerShop shop : shopLocation.values()) { Location newLocation = new Location(signLocation.getWorld(), signLocation.getBlockX(), signLocation.getBlockY(), signLocation.getBlockZ());
if (shop.getSignLocation().equals(signLocation))
return shop; return shopSignLocation.get(newLocation);
}
return null;
} }
public void addShop(PlayerShop shop) { public void addShop(PlayerShop shop) {
shopLocation.put(shop.getShopLocation(), shop); shopLocation.put(shop.getShopLocation(), shop);
shopSignLocation.put(shop.getSignLocation(), shop);
} }
public boolean canPlayerBreakShop(Player player, PlayerShop shop) { public void removeShop(PlayerShop shop) {
shopLocation.remove(shop.getShopLocation());
shopSignLocation.remove(shop.getSignLocation());
}
public boolean canPlayerBreakShop(Player player, PlayerShop shop) { // TODO move to util?
if (player.getUniqueId().equals(shop.getOwnerUUID()) && player.hasPermission("playershops.shop.break")) if (player.getUniqueId().equals(shop.getOwnerUUID()) && player.hasPermission("playershops.shop.break"))
return true; return true;

View File

@ -0,0 +1,11 @@
package com.alttd.playershops.hook;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class WorldGuardHook {
public static boolean canUseShopInRegion(Player player, Location location) {
return true;
}
}

View File

@ -97,6 +97,7 @@ public class PlayerListener extends EventListener {
Component signLine = event.line(0); Component signLine = event.line(0);
if (signLine == null) if (signLine == null)
return; return;
String signLineString = PlainTextComponentSerializer.plainText().serialize(signLine); String signLineString = PlainTextComponentSerializer.plainText().serialize(signLine);
if (!signLineString.equalsIgnoreCase(Config.shopCreationWord)) if (!signLineString.equalsIgnoreCase(Config.shopCreationWord))
return; return;
@ -131,5 +132,4 @@ public class PlayerListener extends EventListener {
} }
} }
} }

View File

@ -0,0 +1,97 @@
package com.alttd.playershops.listener;
import com.alttd.playershops.PlayerShops;
import com.alttd.playershops.gui.ShopManagementGui;
import com.alttd.playershops.handler.ShopHandler;
import com.alttd.playershops.hook.WorldGuardHook;
import com.alttd.playershops.shop.PlayerShop;
import com.alttd.playershops.shop.TransactionError;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
/**
* Dedicated class to listen to transactions for shops.
*
*/
public class TransactionListener extends EventListener {
private final PlayerShops plugin;
public TransactionListener(PlayerShops plugin) {
this.plugin = plugin;
this.register(this.plugin);
}
@EventHandler(ignoreCancelled = true)
public void onShopSignClick(PlayerInteractEvent event) {
if (event.getHand() == EquipmentSlot.OFF_HAND) {
return;
}
Player player = event.getPlayer();
if (!(event.getAction() == Action.RIGHT_CLICK_BLOCK))
return;
Block block = event.getClickedBlock();
if (block == null || Tag.WALL_SIGNS.isTagged(block.getType()))
return;
PlayerShop playerShop = plugin.getShopHandler().getShopBySignLocation(block.getLocation());
if (playerShop == null || !playerShop.isInitialized())
return;
// if we ever need worldguard support add it to the hook
if (!WorldGuardHook.canUseShopInRegion(player, block.getLocation())) {
event.setCancelled(true);
return;
}
if (!player.hasPermission("playershops.shop.use." + playerShop.getType().toString())) {
player.sendMiniMessage("<red>You do not have permission to use " + playerShop.getType().toString() + " shops.", null); // TODO config
}
ShopHandler shopHandler = plugin.getShopHandler();
// Failsafe. If we have a shopsign but no block cancel the event, log error save and unload the shop
if (!shopHandler.isShopMaterial(playerShop.getShopLocation().getBlock())) {
event.setCancelled(true);
shopHandler.removeShop(playerShop);
}
// TODO upgrade this to an util method check if owner/trusted and open management interface
if (playerShop.getOwnerUUID().equals(player.getUniqueId())) {
ShopManagementGui gui = new ShopManagementGui(player.getUniqueId(), playerShop);
gui.open();
return;
}
executeTransaction(player, playerShop);
}
private void executeTransaction(Player player, PlayerShop shop) {
if (shop == null || shop.getItemStack() == null)
return;
int orders = 1;
if (player.isSneaking())
orders = shop.getItemStack().getMaxStackSize();
TransactionError transactionError = shop.executeTransaction(orders, player);
if (transactionError != TransactionError.NONE) {
switch (transactionError) {
case INVENTORY_FULL_PLAYER -> {
}
case CANCELLED -> {
}
case INSUFFICIENT_FUNDS_SHOP -> {
}
}
}
}
}

View File

@ -1,7 +1,11 @@
package com.alttd.playershops.shop; package com.alttd.playershops.shop;
import com.alttd.playershops.PlayerShops; import com.alttd.playershops.PlayerShops;
import com.alttd.playershops.events.PlayerExchangeShopEvent;
import com.alttd.playershops.utils.EconomyUtils;
import com.alttd.playershops.utils.InventoryUtils;
import com.alttd.playershops.utils.ShopUtil; import com.alttd.playershops.utils.ShopUtil;
import com.alttd.playershops.utils.Util;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
@ -27,7 +31,7 @@ public class PlayerShop {
@Getter @Getter
private UUID ownerUUID; private UUID ownerUUID;
@Getter @Setter @Getter @Setter
private ShopType type = ShopType.DEFAULT; private ShopType type = ShopType.NONE;
@Getter @Getter
private final Location signLocation; private final Location signLocation;
@Getter @Getter
@ -76,7 +80,7 @@ public class PlayerShop {
} }
public int getRemainingStock() { public int getRemainingStock() {
return ShopUtil.countItems(getInventory(), getItemStack()); return InventoryUtils.countItems(getInventory(), getItemStack());
} }
public int getRemainingSpace() { public int getRemainingSpace() {
@ -121,7 +125,7 @@ public class PlayerShop {
} }
public boolean isInitialized() { public boolean isInitialized() {
return type != ShopType.DEFAULT; return type != ShopType.NONE;
} }
public void updateSign() { public void updateSign() {
@ -149,4 +153,108 @@ public class PlayerShop {
} }
}.runTaskLater(PlayerShops.getInstance(), 2L); }.runTaskLater(PlayerShops.getInstance(), 2L);
} }
public double getPricePerItem() {
double pricePer = this.getPrice() / this.getAmount();
return this.getPrice() / this.getAmount();
}
public void removeBalance(double amount) {
this.balance -= amount;
}
public void addBalance(double amount) {
this.balance += amount;
}
public TransactionError executeTransaction(int orders, Player player) {
return switch (getType()) {
case SELL -> executeSellTransaction(orders, player);
case BUY -> executeBuyTransaction(orders, player);
case GAMBLE -> executeGambleTransaction(orders, player);
default -> TransactionError.NONE; // This should not happen
};
}
private TransactionError executeSellTransaction(int orders, Player player) {
ItemStack itemStack = getItemStack().clone();
double price = getPrice();
if (orders == itemStack.getMaxStackSize()) {
itemStack.setAmount(orders);
price = getPricePerItem() * orders;
}
int shopItems = InventoryUtils.countItems(getInventory(), itemStack);
if (shopItems < itemStack.getAmount())
return TransactionError.INSUFFICIENT_FUNDS_SHOP;
boolean hasFunds = EconomyUtils.hasSufficientFunds(player, price);
if (!hasFunds)
return TransactionError.INSUFFICIENT_FUNDS_PLAYER;
boolean hasRoom = EconomyUtils.canAcceptFunds(this, price);
if (!hasRoom)
return TransactionError.INVENTORY_FULL_SHOP;
boolean playerHasRoom = InventoryUtils.hasRoom(player.getInventory(), itemStack);
if (!playerHasRoom)
return TransactionError.INVENTORY_FULL_PLAYER;
PlayerExchangeShopEvent playerExchangeShopEvent = new PlayerExchangeShopEvent(player, this);
if (Util.callCancellableEvent(playerExchangeShopEvent)) {
return TransactionError.CANCELLED;
}
InventoryUtils.removeItem(getInventory(), itemStack);
EconomyUtils.removeFunds(player, price);
addBalance(price);
InventoryUtils.addItem(player.getInventory(), itemStack);
player.updateInventory();
return TransactionError.NONE;
}
private TransactionError executeBuyTransaction(int orders, Player player) {
ItemStack itemStack = getItemStack().clone();
double price = getPrice();
if (orders == itemStack.getMaxStackSize()) {
itemStack.setAmount(orders);
price = getPricePerItem() * orders;
}
int playerItems = InventoryUtils.countItems(player.getInventory(), itemStack);
if (playerItems < itemStack.getAmount())
return TransactionError.INSUFFICIENT_FUNDS_PLAYER;
boolean hasFunds = EconomyUtils.hasSufficientFunds(this, price);
if (!hasFunds)
return TransactionError.INSUFFICIENT_FUNDS_SHOP;
boolean hasRoom = EconomyUtils.canAcceptFunds(player, price);
if (!hasRoom)
return TransactionError.INVENTORY_FULL_PLAYER;
boolean shopHasRoom = InventoryUtils.hasRoom(getInventory(), itemStack);
if (!shopHasRoom)
return TransactionError.INVENTORY_FULL_SHOP;
PlayerExchangeShopEvent playerExchangeShopEvent = new PlayerExchangeShopEvent(player, this);
if (Util.callCancellableEvent(playerExchangeShopEvent)) {
return TransactionError.CANCELLED;
}
InventoryUtils.removeItem(player.getInventory(), itemStack);
removeBalance(price);
EconomyUtils.addFunds(player, price);
InventoryUtils.addItem(getInventory(), itemStack);
player.updateInventory();
return TransactionError.NONE;
}
private TransactionError executeGambleTransaction(int orders, Player player) {
return TransactionError.NONE;
}
} }

View File

@ -4,7 +4,7 @@ import com.alttd.playershops.config.ShopTypeConfig;
public enum ShopType { public enum ShopType {
DEFAULT(), NONE(),
SELL(), SELL(),
BUY(), BUY(),
GAMBLE(); GAMBLE();

View File

@ -0,0 +1,58 @@
package com.alttd.playershops.utils;
import com.alttd.playershops.PlayerShops;
import com.alttd.playershops.shop.PlayerShop;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.entity.Player;
// TODO document
public class EconomyUtils {
//check to see if the player has enough funds to take out [amount]
//return false if they do not
public static boolean hasSufficientFunds(Player player, double amount) {
double balance = PlayerShops.getInstance().getEconomy().getBalance(player);
return (balance >= amount);
}
public static boolean hasSufficientFunds(PlayerShop shop, double amount) {
double balance = shop.getBalance();
return (balance >= amount);
}
//gets the current funds of the player
public static double getFunds(Player player) {
return PlayerShops.getInstance().getEconomy().getBalance(player);
}
//removes [amount] of funds from the player
//return false if the player did not have sufficient funds or if something went wrong
public static boolean removeFunds(Player player, double amount) {
EconomyResponse response = PlayerShops.getInstance().getEconomy().withdrawPlayer(player, amount);
return response.transactionSuccess();
}
//adds [amount] of funds to the player
//return false if the player is offline
public static boolean addFunds(Player player, double amount) {
if(player.isOnline()) {
EconomyResponse response = PlayerShops.getInstance().getEconomy().depositPlayer(player, amount);
return response.transactionSuccess();
} else {
return false;
// int temp = PlayerShops.getInstance().Earnings.getInt(player.getUniqueId() + ".earnings");
// PlayerShops.getInstance().Earnings.set(player.getUniqueId() + ".earnings", temp + amount);
// PlayerShops.getInstance().Earnings.save();
}
}
public static boolean canAcceptFunds(Player player, double price) {
// if we ever need to limit the maximum balance a player can have this is the place
return true;
}
public static boolean canAcceptFunds(PlayerShop shop, double price) {
// if we ever need to limit the maximum balance a shop can have this is the place
return true;
}
}

View File

@ -0,0 +1,119 @@
package com.alttd.playershops.utils;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.HashMap;
public class InventoryUtils {
/**
* Counts the number of items in the given inventory where
* Util.matches(inventory item, item) is true.
*
* @param inv
* The inventory to search
* @param item
* The ItemStack to search for
* @return The number of items that match in this inventory.
*/
public static int countItems(Inventory inv, ItemStack item) {
int items = 0;
for (ItemStack iStack : inv.getContents()) {
if (iStack == null)
continue;
if (ShopUtil.matches(item, iStack)) {
items += iStack.getAmount();
}
}
return items;
}
// TODO DOCS
//removes itemstack from inventory
//returns the amount of items it could not remove
public static int removeItem(Inventory inventory, ItemStack itemStack) {
if (inventory == null)
return itemStack.getAmount();
if (itemStack == null || itemStack.getAmount() <= 0)
return 0;
ItemStack[] contents = inventory.getContents();
int amount = itemStack.getAmount();
for (ItemStack stack : contents) {
if (stack != null) {
if (ShopUtil.matches(stack, itemStack)) {
if (stack.getAmount() > amount) {
stack.setAmount(stack.getAmount() - amount);
inventory.setContents(contents);
return 0;
} else if (stack.getAmount() == amount) {
stack.setType(Material.AIR);
inventory.setContents(contents);
return 0;
} else {
amount -= stack.getAmount();
stack.setType(Material.AIR);
}
}
}
}
inventory.setContents(contents);
return amount;
}
//takes an ItemStack and splits it up into multiple ItemStacks with correct stack sizes
//then adds those items to the given inventory
public static int addItem(Inventory inventory, ItemStack itemStack) {
if (inventory == null)
return itemStack.getAmount();
if (itemStack.getAmount() <= 0)
return 0;
ArrayList<ItemStack> itemStacksAdding = new ArrayList<>();
//break up the itemstack into multiple ItemStacks with correct stack size
int fullStacks = itemStack.getAmount() / itemStack.getMaxStackSize();
int partialStack = itemStack.getAmount() % itemStack.getMaxStackSize();
for (int i = 0; i < fullStacks; i++) {
ItemStack is = itemStack.clone();
is.setAmount(is.getMaxStackSize());
itemStacksAdding.add(is);
}
ItemStack is = itemStack.clone();
is.setAmount(partialStack);
if (partialStack > 0)
itemStacksAdding.add(is);
//try adding all items from itemStacksAdding and return number of ones you couldn't add
int amount = 0;
for (ItemStack addItem : itemStacksAdding) {
HashMap<Integer, ItemStack> noAdd = inventory.addItem(addItem);
for (ItemStack noAddItemstack : noAdd.values()) {
amount += noAddItemstack.getAmount();
}
}
return amount;
}
public static boolean hasRoom(Inventory inventory, ItemStack itemStack) {
if (inventory == null)
return false;
if (itemStack.getAmount() <= 0)
return true;
int overflow = addItem(inventory, itemStack);
//revert back if inventory cannot hold all of the items
if (overflow > 0) {
ItemStack revert = itemStack.clone();
revert.setAmount(revert.getAmount() - overflow);
InventoryUtils.removeItem(inventory, revert);
return false;
}
removeItem(inventory, itemStack);
return true;
}
}

View File

@ -0,0 +1,83 @@
package com.alttd.playershops.utils;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.bukkit.Bukkit;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import java.util.HashMap;
public class Util {
private static MiniMessage miniMessage = null;
public static HashMap<String, String> colors;
static { // this might be in minimessage already?
colors = new HashMap<>();
colors.put("&0", "<black>");
colors.put("&1", "<dark_blue>");
colors.put("&2", "<dark_green>");
colors.put("&3", "<dark_aqua>");
colors.put("&4", "<dark_red>");
colors.put("&5", "<dark_purple>");
colors.put("&6", "<gold>");
colors.put("&7", "<gray>");
colors.put("&8", "<dark_gray>");
colors.put("&9", "<blue>");
colors.put("&a", "<green>");
colors.put("&b", "<aqua>");
colors.put("&c", "<red>");
colors.put("&d", "<light_purple>");
colors.put("&e", "<yellow>");
colors.put("&f", "<white>");
colors.put("&l", "<bold>");
colors.put("&o", "<italic>");
}
public static String parseColors(String message) {
for (String key : colors.keySet()) {
if (message.contains(key)) {
message = message.replace(key, colors.get(key));
}
}
return message;
}
private static MiniMessage miniMessage() {
if (miniMessage == null)
miniMessage = MiniMessage.miniMessage();
return miniMessage;
}
public static Component parseMiniMessage(String message, TagResolver tagResolver) {
message = parseColors(message);
if (tagResolver == null) {
return miniMessage().deserialize(message);
} else {
return miniMessage().deserialize(message, tagResolver);
}
}
public static String capitalize(String string) {
if (string.length() <= 1)
return string.toUpperCase();
string = string.toLowerCase();
return string.substring(0, 1).toUpperCase() + string.toLowerCase().substring(1);
}
/**
* Call an event and check it is cancelled.
*
* @param event The event implement the Cancellable interface.
* @return The event is cancelled.
*/
public static boolean callCancellableEvent(Cancellable event) {
if (!(event instanceof Event)) {
throw new IllegalArgumentException("Cancellable must is event implement");
}
Bukkit.getPluginManager().callEvent((Event) event);
return event.isCancelled();
}
}