Weird sign shop stuff.

This commit is contained in:
AppleDash 2017-01-10 17:09:18 -05:00
parent 934d92fbf9
commit 4df22729aa
10 changed files with 271 additions and 27 deletions

View File

@ -39,8 +39,17 @@ public class TransactionResult {
}
public enum Status {
SUCCESS,
SUCCESS("Success."),
ERR_NOT_ENOUGH_FUNDS("Not enough money is available for you to complete that transaction.");
ERR_NOT_ENOUGH_FUNDS
private final String message;
Status(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
}

View File

@ -7,6 +7,7 @@ import org.appledash.saneeconomysignshop.listeners.SignChangeListener;
import org.appledash.saneeconomysignshop.signshop.SignShopManager;
import org.appledash.saneeconomysignshop.signshop.storage.SignShopStorageFlatfile;
import org.appledash.saneeconomysignshop.util.ItemDatabase;
import org.appledash.saneeconomysignshop.util.LimitManager;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
@ -19,6 +20,7 @@ import java.io.File;
public class SaneEconomySignShop extends JavaPlugin {
private ISaneEconomy saneEconomy;
private final SignShopManager signShopManager = new SignShopManager(new SignShopStorageFlatfile(new File(getDataFolder(), "shops.db")));
private final LimitManager limitManager = new LimitManager();
@Override
public void onEnable() {
@ -50,4 +52,8 @@ public class SaneEconomySignShop extends JavaPlugin {
public ISaneEconomy getSaneEconomy() {
return saneEconomy;
}
public LimitManager getLimitManager() {
return limitManager;
}
}

View File

@ -1,12 +1,11 @@
package org.appledash.saneeconomysignshop.listeners;
import org.appledash.saneeconomy.economy.EconomyManager;
import org.appledash.saneeconomy.economy.economable.Economable;
import org.appledash.saneeconomy.economy.transaction.Transaction;
import org.appledash.saneeconomy.economy.transaction.TransactionReason;
import org.appledash.saneeconomy.economy.transaction.TransactionResult;
import org.appledash.saneeconomy.utils.MessageUtils;
import org.appledash.saneeconomysignshop.SaneEconomySignShop;
import org.appledash.saneeconomysignshop.signshop.ShopTransaction;
import org.appledash.saneeconomysignshop.signshop.SignShop;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@ -84,26 +83,30 @@ public class InteractListener implements Listener {
private void doBuy(SignShop shop, Player player) {
EconomyManager ecoMan = plugin.getSaneEconomy().getEconomyManager();
int quantity = player.isSneaking() ? 1 : shop.getQuantity();
double price = shop.getBuyPrice(quantity);
if (!ecoMan.hasBalance(Economable.wrap(player), price)) {
MessageUtils.sendMessage(player, "You do not have enough money to buy {1} {2}.", quantity, shop.getItem());
ShopTransaction shopTransaction = shop.makeTransaction(player, ShopTransaction.TransactionDirection.BUY, quantity);
if (!plugin.getLimitManager().shouldAllowTransaction(shopTransaction)) {
MessageUtils.sendMessage(player, "You have reached your buying limit for the time being. Try back in an hour or so.");
return;
}
TransactionResult result = ecoMan.transact(new Transaction(Economable.wrap(player), Economable.PLUGIN, price, TransactionReason.PLUGIN_TAKE));
plugin.getLimitManager().setRemainingLimit(player, ShopTransaction.TransactionDirection.BUY, shop.getItem(), plugin.getLimitManager().getRemainingLimit(player, ShopTransaction.TransactionDirection.BUY, shop.getItem()) - quantity);
Transaction ecoTransaction = shopTransaction.makeEconomyTransaction();
TransactionResult result = ecoMan.transact(ecoTransaction);
if (result.getStatus() != TransactionResult.Status.SUCCESS) {
MessageUtils.sendMessage(player, "An error occurred attempting to perform that transaction: {1}", result.getStatus());
return;
}
ItemStack stack = shop.getItem().clone();
ItemStack stack = shop.getItemStack().clone();
stack.setAmount(quantity);
player.getInventory().addItem(stack);
MessageUtils.sendMessage(player, "You have bought {1} {2} for {3}.", quantity, shop.getItem(), ecoMan.getCurrency().formatAmount(price));
LOGGER.info(String.format("%s just bought %s for %s.", player.getName(), shop.getItem(), ecoMan.getCurrency().formatAmount(price)));
MessageUtils.sendMessage(player, "You have bought {1} {2} for {3}.", quantity, shop.getItemStack().getType().name(), ecoMan.getCurrency().formatAmount(shopTransaction.getPrice()));
LOGGER.info(String.format("%s just bought %s for %s.", player.getName(), shop.getItemStack(), ecoMan.getCurrency().formatAmount(shopTransaction.getPrice())));
}
private void doSell(SignShop shop, Player player) { // TODO: Selling enchanted items
@ -111,17 +114,29 @@ public class InteractListener implements Listener {
int quantity = player.isSneaking() ? 1 : shop.getQuantity();
double price = shop.getSellPrice(quantity);
if (!player.getInventory().containsAtLeast(new ItemStack(shop.getItem()), quantity)) {
MessageUtils.sendMessage(player, "You do not have {1} {2}!", quantity, shop.getItem());
if (!player.getInventory().containsAtLeast(new ItemStack(shop.getItemStack()), quantity)) {
MessageUtils.sendMessage(player, "You do not have {1} {2}!", quantity, shop.getItemStack().getType().name());
return;
}
ItemStack stack = shop.getItem().clone();
stack.setAmount(quantity);
ShopTransaction shopTransaction = shop.makeTransaction(player, ShopTransaction.TransactionDirection.SELL, quantity);
if (!plugin.getLimitManager().shouldAllowTransaction(shopTransaction)) {
MessageUtils.sendMessage(player, "You have reached your selling limit for the time being. Try back in an hour or so.");
return;
}
plugin.getLimitManager().setRemainingLimit(player, ShopTransaction.TransactionDirection.SELL, shop.getItem(), plugin.getLimitManager().getRemainingLimit(player, ShopTransaction.TransactionDirection.BUY, shop.getItem()) - quantity);
ItemStack stack = shop.getItemStack().clone();
stack.setAmount(quantity);
player.getInventory().removeItem(stack); // FIXME: This does not remove items with damage values that were detected by contains()
ecoMan.transact(new Transaction(Economable.PLUGIN, Economable.wrap(player), price, TransactionReason.PLUGIN_GIVE));
MessageUtils.sendMessage(player, "You have sold {1} {2} for {3}.", quantity, shop.getItem(), ecoMan.getCurrency().formatAmount(price));
LOGGER.info(String.format("%s just sold %s for %s.", player.getName(), shop.getItem(), ecoMan.getCurrency().formatAmount(price)));
ecoMan.transact(shopTransaction.makeEconomyTransaction());
MessageUtils.sendMessage(player, "You have sold {1} {2} for {3}.", quantity, shop.getItemStack().getType().name(), ecoMan.getCurrency().formatAmount(price));
LOGGER.info(String.format("%s just sold %s for %s.", player.getName(), shop.getItemStack(), ecoMan.getCurrency().formatAmount(price)));
}
}

View File

@ -50,7 +50,7 @@ public class SignChangeListener implements Listener {
plugin.getSignShopManager().addSignShop(signShop);
evt.setLine(0, ChatColor.translateAlternateColorCodes('&', plugin.getConfig().getString("admin-shop-title")));
MessageUtils.sendMessage(evt.getPlayer(), "Sign shop created!");
MessageUtils.sendMessage(evt.getPlayer(), "Item: {1} x {2}", signShop.getQuantity(), signShop.getItem());
MessageUtils.sendMessage(evt.getPlayer(), "Item: {1} x {2}", signShop.getQuantity(), signShop.getItemStack());
if (signShop.canBuy()) { // The player be buying from the shop, not the other way around.
MessageUtils.sendMessage(evt.getPlayer(), "Will sell to players for {!}.",

View File

@ -0,0 +1,60 @@
package org.appledash.saneeconomysignshop.signshop;
import org.appledash.saneeconomy.economy.economable.Economable;
import org.appledash.saneeconomy.economy.transaction.Transaction;
import org.appledash.saneeconomy.economy.transaction.TransactionReason;
import org.appledash.saneeconomysignshop.util.ItemInfo;
import org.bukkit.entity.Player;
/**
* Created by appledash on 1/1/17.
* Blackjack is still best pony.
*/
public class ShopTransaction {
// Direction is always what the player is doing. BUY = player is buying from shop.
private final TransactionDirection direction;
private final Player player;
private final ItemInfo item;
private final int quantity;
private final double price;
public ShopTransaction(TransactionDirection direction, Player player, ItemInfo item, int quantity, double price) {
this.direction = direction;
this.player = player;
this.item = item;
this.quantity = quantity;
this.price = price;
}
public TransactionDirection getDirection() {
return direction;
}
public Player getPlayer() {
return player;
}
public ItemInfo getItem() {
return item;
}
public int getQuantity() {
return quantity;
}
public double getPrice() {
return price;
}
public Transaction makeEconomyTransaction() {
if (direction == TransactionDirection.BUY) {
return new Transaction(Economable.wrap(player), Economable.PLUGIN, price, TransactionReason.PLUGIN_TAKE);
} else {
return new Transaction(Economable.PLUGIN, Economable.wrap(player), price, TransactionReason.PLUGIN_GIVE);
}
}
public enum TransactionDirection {
BUY, SELL
}
}

View File

@ -1,8 +1,10 @@
package org.appledash.saneeconomysignshop.signshop;
import org.appledash.saneeconomysignshop.signshop.ShopTransaction.TransactionDirection;
import org.appledash.saneeconomysignshop.util.ItemInfo;
import org.appledash.saneeconomysignshop.util.SerializableLocation;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.io.Serializable;
@ -49,10 +51,18 @@ public class SignShop implements Serializable {
* Get the type of item this SignShop is selling
* @return Material representing item/block type
*/
public ItemStack getItem() {
public ItemStack getItemStack() {
return item.toItemStack();
}
/**
* Get the ItemInfo for the item this SignShop is selling
* @return ItemInfo representing the type and quantity of item
*/
public ItemInfo getItem() {
return item;
}
/**
* Get the price that the player can buy this item from the server for
* @return Buy price for this.getQuantity() items
@ -120,4 +130,8 @@ public class SignShop implements Serializable {
public int getQuantity() {
return quantity;
}
public ShopTransaction makeTransaction(Player player, TransactionDirection direction, int quantity) {
return new ShopTransaction(direction, player, item, quantity, (direction == TransactionDirection.BUY) ? getBuyPrice(quantity) : getSellPrice(quantity));
}
}

View File

@ -0,0 +1,32 @@
package org.appledash.saneeconomysignshop.util;
import java.util.HashMap;
import java.util.function.Supplier;
/**
* Created by appledash on 1/1/17.
* Blackjack is still best pony.
*/
public class DefaultHashMap<K, V> extends HashMap<K, V> {
private final Supplier<V> defaultSupplier;
public DefaultHashMap(Supplier<V> defaultSupplier) {
if (defaultSupplier == null) {
throw new NullPointerException("defaultSupplier is null");
}
this.defaultSupplier = defaultSupplier;
}
@Override
public V get(Object k) {
V v = super.get(k);
if (v == null) {
v = defaultSupplier.get();
this.put((K) k, v);
}
return v;
}
}

View File

@ -4,27 +4,48 @@ import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.io.Serializable;
import java.util.Objects;
/**
* Created by appledash on 11/3/16.
* Blackjack is still best pony.
*/
public class ItemInfo implements Serializable {
private Material id;
private short damage;
private int amount;
private final Material material;
private final short damage;
private final int amount;
public ItemInfo(ItemStack stack) {
this(stack.getType(), stack.getDurability(), stack.getAmount());
}
public ItemInfo(Material id, short damage, int amount) {
this.id = id;
public ItemInfo(Material material, short damage, int amount) {
this.material = material;
this.damage = damage;
this.amount = amount;
}
public ItemStack toItemStack() {
return new ItemStack(id, amount, damage);
return new ItemStack(material, amount, damage);
}
public Material getMaterial() {
return material;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ItemInfo)) {
return false;
}
ItemInfo other = ((ItemInfo) o);
return (other.material == this.material) && (other.damage == this.damage);
}
@Override
public int hashCode() {
return Objects.hash(material, damage);
}
}

View File

@ -0,0 +1,26 @@
package org.appledash.saneeconomysignshop.util;
/**
* Created by appledash on 1/1/17.
* Blackjack is still best pony.
*/
public class ItemLimits {
// The default limit for items that have no limit.
public static final ItemLimits DEFAULT = new ItemLimits(10, 1);
private final int limit;
private final int hourlyGain;
public ItemLimits(int limit, int hourlyGain) {
this.limit = limit;
this.hourlyGain = hourlyGain;
}
public int getHourlyGain() {
return hourlyGain;
}
public int getLimit() {
return limit;
}
}

View File

@ -0,0 +1,61 @@
package org.appledash.saneeconomysignshop.util;
import org.appledash.saneeconomysignshop.signshop.ShopTransaction;
import org.appledash.saneeconomysignshop.signshop.ShopTransaction.TransactionDirection;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Created by appledash on 1/1/17.
* Blackjack is still best pony.
*/
public class LimitManager {
private final Map<TransactionDirection, Map<ItemInfo, ItemLimits>> itemLimits = new DefaultHashMap<>(() -> new DefaultHashMap<>(() -> ItemLimits.DEFAULT));
// This is a slightly complex data structure. It works like this:
// It's a map of (limit types to (maps of players to (maps of materials to the remaning limit))).
// All the TransactionDirections defaults to an empty map, which defaults to an empty map, which defaults to 0.
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final Map<TransactionDirection, Map<UUID, Map<ItemInfo, Integer>>> playerLimits = new DefaultHashMap<>(() -> new DefaultHashMap<>(() -> new DefaultHashMap<>(() -> 0)));
public int getRemainingLimit(Player player, TransactionDirection type, ItemInfo stack) {
return playerLimits.get(type).get(player.getUniqueId()).get(stack);
}
public void setRemainingLimit(Player player, TransactionDirection type, ItemInfo stack, int limit) {
if (playerLimits.get(type).get(player.getUniqueId()).get(stack) == -1) {
return;
}
limit = Math.min(limit, itemLimits.get(type).get(stack).getLimit());
limit = Math.max(0, limit);
playerLimits.get(type).get(player.getUniqueId()).put(stack, limit);
}
public boolean shouldAllowTransaction(ShopTransaction transaction) {
return getRemainingLimit(transaction.getPlayer(), transaction.getDirection(), transaction.getItem()) >= transaction.getQuantity();
}
public void incrementLimitsHourly() {
// For every limit type
// For every player
// For every limit
// Increment limit by the limit for the specific direction and item.
playerLimits.forEach((transactionDirection, playerToLimit) -> {
playerToLimit.forEach((playerUuid, itemToLimit) -> {
Map<ItemInfo, Integer> newLimits = new HashMap<>();
itemToLimit.forEach((itemInfo, currentLimit) -> {
newLimits.put(itemInfo, currentLimit + (itemLimits.get(transactionDirection).get(itemInfo).getHourlyGain()));
});
itemToLimit.putAll(newLimits);
});
});
}
}