Transactions now use Event-Listener system

This commit is contained in:
Acrobot 2012-08-10 18:56:16 +02:00
parent 92aeee4a86
commit a3eaff47cd
18 changed files with 922 additions and 120 deletions

View File

@ -15,9 +15,12 @@ import com.Acrobot.ChestShop.Listeners.ItemInfoListener;
import com.Acrobot.ChestShop.Listeners.Player.PlayerConnect;
import com.Acrobot.ChestShop.Listeners.Player.PlayerInteract;
import com.Acrobot.ChestShop.Listeners.Player.ShortNameSaver;
import com.Acrobot.ChestShop.Listeners.Transaction.EmptyShopDeleter;
import com.Acrobot.ChestShop.Listeners.Transaction.TransactionLogger;
import com.Acrobot.ChestShop.Listeners.Transaction.TransactionMessageSender;
import com.Acrobot.ChestShop.Listeners.Shop.PostTransaction.EconomicModule;
import com.Acrobot.ChestShop.Listeners.Shop.PostTransaction.ItemManager;
import com.Acrobot.ChestShop.Listeners.Shop.PreTransaction.*;
import com.Acrobot.ChestShop.Listeners.Shop.PostTransaction.EmptyShopDeleter;
import com.Acrobot.ChestShop.Listeners.Shop.PostTransaction.TransactionLogger;
import com.Acrobot.ChestShop.Listeners.Shop.PostTransaction.TransactionMessageSender;
import com.Acrobot.ChestShop.Logging.FileFormatter;
import com.avaje.ebean.EbeanServer;
import com.lennardf1989.bukkitex.Database;
@ -37,6 +40,9 @@ import java.util.List;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import static com.Acrobot.ChestShop.Config.Property.ALLOW_PARTIAL_TRANSACTIONS;
import static com.Acrobot.ChestShop.Config.Property.SHOP_INTERACTION_INTERVAL;
/**
* Main file of the plugin
*
@ -137,6 +143,7 @@ public class ChestShop extends JavaPlugin {
registerEvent(new SignChange());
registerEvent(new EntityExplode());
registerEvent(new PlayerConnect());
registerEvent(new PlayerInteract());
registerEvent(new ItemInfoListener());
@ -144,9 +151,24 @@ public class ChestShop extends JavaPlugin {
registerEvent(new TransactionLogger());
registerEvent(new TransactionMessageSender());
registerEvent(new ShortNameSaver());
registerEvent(new EconomicModule());
registerEvent(new ItemManager());
registerEvent(new PlayerInteract(Config.getInteger(Property.SHOP_INTERACTION_INTERVAL)));
registerEvent(new CreativeModeIgnorer());
registerEvent(new PermissionChecker());
registerEvent(new PriceValidator());
registerEvent(new ShopValidator());
registerEvent(new StockFittingChecker());
registerEvent(new ErrorMessageSender());
registerEvent(new SpamClickProtector(Config.getInteger(SHOP_INTERACTION_INTERVAL)));
if (Config.getBoolean(ALLOW_PARTIAL_TRANSACTIONS)) {
registerEvent(new PartialTransactionModule());
} else {
registerEvent(new AmountAndPriceChecker());
}
registerEvent(new ShortNameSaver());
}
public void registerEvent(Listener listener) {

View File

@ -1,47 +1,112 @@
package com.Acrobot.ChestShop.Events;
import com.Acrobot.ChestShop.Shop.Shop;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.TRANSACTION_SUCCESFUL;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType;
/**
* @author Acrobot
*/
public class PreTransactionEvent extends Event implements Cancellable {
public class PreTransactionEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final Shop shop;
private final Player player;
private final TransactionEvent.Type transactionType;
private final Player client;
private OfflinePlayer owner;
private boolean isCancelled = false;
private final TransactionType transactionType;
private final Sign sign;
public PreTransactionEvent(Shop shop, Player player, TransactionEvent.Type type) {
this.shop = shop;
this.player = player;
private Inventory ownerInventory;
private Inventory clientInventory;
private ItemStack[] items;
private double price;
private TransactionOutcome transactionOutcome = TRANSACTION_SUCCESFUL;
public PreTransactionEvent(Inventory ownerInventory, Inventory clientInventory, ItemStack[] items, double price, Player client, OfflinePlayer owner, Sign sign, TransactionType type) {
this.ownerInventory = ownerInventory;
this.clientInventory = (clientInventory == null ? client.getInventory() : clientInventory);
this.items = items;
this.price = price;
this.client = client;
this.owner = owner;
this.sign = sign;
this.transactionType = type;
}
public Shop getShop() {
return shop;
public Sign getSign() {
return sign;
}
public Player getPlayer() {
return player;
public double getPrice() {
return price;
}
public TransactionEvent.Type getTransactionType() {
public void setPrice(double price) {
this.price = price;
}
public void setStock(ItemStack... stock) {
items = stock;
}
public ItemStack[] getStock() {
return items;
}
public Player getClient() {
return client;
}
public OfflinePlayer getOwner() {
return owner;
}
public void setOwner(OfflinePlayer owner) {
this.owner = owner;
}
public Inventory getOwnerInventory() {
return ownerInventory;
}
public void setOwnerInventory(Inventory ownerInventory) {
this.ownerInventory = ownerInventory;
}
public void setClientInventory(Inventory clientInventory) {
this.clientInventory = clientInventory;
}
public Inventory getClientInventory() {
return clientInventory;
}
public TransactionType getTransactionType() {
return transactionType;
}
public boolean isCancelled() {
return isCancelled;
return transactionOutcome != TRANSACTION_SUCCESFUL;
}
public void setCancelled(boolean b) {
this.isCancelled = b;
public TransactionOutcome getTransactionOutcome() {
return transactionOutcome;
}
public void setCancelled(TransactionOutcome reason) {
transactionOutcome = reason;
}
public HandlerList getHandlers() {
@ -51,4 +116,30 @@ public class PreTransactionEvent extends Event implements Cancellable {
public static HandlerList getHandlerList() {
return handlers;
}
public enum TransactionOutcome {
SHOP_DOES_NOT_BUY_THIS_ITEM,
SHOP_DOES_NOT_SELL_THIS_ITEM,
CLIENT_DOES_NOT_HAVE_PERMISSION,
CLIENT_DOES_NOT_HAVE_ENOUGH_MONEY,
SHOP_DOES_NOT_HAVE_ENOUGH_MONEY,
NOT_ENOUGH_SPACE_IN_CHEST,
NOT_ENOUGH_SPACE_IN_INVENTORY,
NOT_ENOUGH_STOCK_IN_CHEST,
NOT_ENOUGH_STOCK_IN_INVENTORY,
INVALID_SHOP,
SPAM_CLICKING_PROTECTION,
CREATIVE_MODE_PROTECTION,
SHOP_IS_RESTRICTED,
OTHER, //For plugin use!
TRANSACTION_SUCCESFUL
}
}

View File

@ -1,10 +1,11 @@
package com.Acrobot.ChestShop.Events;
import com.Acrobot.ChestShop.Containers.Container;
import org.bukkit.OfflinePlayer;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
/**
@ -12,65 +13,81 @@ import org.bukkit.inventory.ItemStack;
*/
public class TransactionEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final TransactionType type;
private Container container;
private Sign sign;
private final Inventory ownerInventory;
private final Inventory clientInventory;
private Player client;
private String owner;
private final Player client;
private final OfflinePlayer owner;
private ItemStack item;
private int itemAmount;
private double price;
private final ItemStack[] stock;
private final double price;
private Type transactionType;
private final Sign sign;
public TransactionEvent(PreTransactionEvent event, Sign sign) {
this.type = event.getTransactionType();
this.ownerInventory = event.getOwnerInventory();
this.clientInventory = event.getClientInventory();
this.client = event.getClient();
this.owner = event.getOwner();
this.stock = event.getStock();
this.price = event.getPrice();
public TransactionEvent(Type transactionType, Container container, Sign sign, Player client, String owner, ItemStack item, double price) {
this.container = container;
this.sign = sign;
}
public TransactionEvent(TransactionType type, Inventory ownerInventory, Inventory clientInventory, Player client, OfflinePlayer owner, ItemStack[] stock, double price, Sign sign){
this.type = type;
this.ownerInventory = ownerInventory;
this.clientInventory = clientInventory;
this.client = client;
this.owner = owner;
this.item = item;
this.itemAmount = item.getAmount();
this.transactionType = transactionType;
this.stock = stock;
this.price = price;
this.sign = sign;
}
public Type getTransactionType() {
return transactionType;
public TransactionType getTransactionType() {
return type;
}
public Container getContainer() {
return container;
public Inventory getOwnerInventory() {
return ownerInventory;
}
public Sign getSign() {
return sign;
public Inventory getClientInventory() {
return clientInventory;
}
public Player getClient() {
return client;
}
public String getOwner() {
public OfflinePlayer getOwner() {
return owner;
}
public ItemStack getItem() {
return item;
}
public int getItemAmount() {
return itemAmount;
public ItemStack[] getStock() {
return stock;
}
public double getPrice() {
return price;
}
public Sign getSign() {
return sign;
}
public HandlerList getHandlers() {
return handlers;
}
@ -79,7 +96,7 @@ public class TransactionEvent extends Event {
return handlers;
}
public enum Type {
public enum TransactionType {
BUY,
SELL
}

View File

@ -0,0 +1,34 @@
package com.Acrobot.ChestShop.Listeners.Shop.PostTransaction;
import com.Acrobot.ChestShop.Economy.Economy;
import com.Acrobot.ChestShop.Events.TransactionEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.BUY;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.SELL;
/**
* @author Acrobot
*/
public class EconomicModule implements Listener {
@EventHandler
public static void onBuyTransaction(TransactionEvent event) {
if (event.getTransactionType() != BUY) {
return;
}
Economy.subtract(event.getClient().getName(), event.getPrice());
Economy.add(event.getOwner().getName(), event.getPrice());
}
@EventHandler
public static void onSellTransaction(TransactionEvent event) {
if (event.getTransactionType() != SELL) {
return;
}
Economy.subtract(event.getOwner().getName(), event.getPrice());
Economy.add(event.getClient().getName(), event.getPrice());
}
}

View File

@ -0,0 +1,41 @@
package com.Acrobot.ChestShop.Listeners.Shop.PostTransaction;
import com.Acrobot.ChestShop.Config.Config;
import com.Acrobot.ChestShop.Config.Property;
import com.Acrobot.ChestShop.Events.TransactionEvent;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
/**
* @author Acrobot
*/
public class EmptyShopDeleter implements Listener {
@EventHandler
public static void onTransaction(TransactionEvent event) {
if (event.getTransactionType() != TransactionEvent.TransactionType.BUY) {
return;
}
if (shopShouldBeRemoved(event.getOwnerInventory())) {
event.getSign().getBlock().setType(Material.AIR);
event.getOwnerInventory().addItem(new ItemStack(Material.SIGN, 1));
}
}
private static boolean shopShouldBeRemoved(Inventory inventory) {
return Config.getBoolean(Property.REMOVE_EMPTY_SHOPS) && isEmpty(inventory);
}
public static boolean isEmpty(Inventory inventory) {
for (ItemStack item : inventory.getContents()) {
if (item != null) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,50 @@
package com.Acrobot.ChestShop.Listeners.Shop.PostTransaction;
import com.Acrobot.Breeze.Utils.InventoryUtil;
import com.Acrobot.ChestShop.Events.TransactionEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.BUY;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.SELL;
/**
* @author Acrobot
*/
public class ItemManager implements Listener {
@EventHandler
public static void shopItemRemover(TransactionEvent event) {
if (event.getTransactionType() != BUY) {
return;
}
removeItems(event.getOwnerInventory(), event.getStock());
addItems(event.getClientInventory(), event.getStock());
event.getClient().updateInventory();
}
@EventHandler
public static void inventoryItemRemover(TransactionEvent event) {
if (event.getTransactionType() != SELL) {
return;
}
removeItems(event.getClientInventory(), event.getStock());
addItems(event.getOwnerInventory(), event.getStock());
event.getClient().updateInventory();
}
private static void removeItems(Inventory inventory, ItemStack[] items) {
for (ItemStack item : items) {
InventoryUtil.remove(item, inventory);
}
}
private static void addItems(Inventory inventory, ItemStack[] items) {
inventory.addItem(items);
}
}

View File

@ -1,4 +1,4 @@
package com.Acrobot.ChestShop.Listeners.Transaction;
package com.Acrobot.ChestShop.Listeners.Shop.PostTransaction;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Config.Config;
@ -13,7 +13,7 @@ import org.bukkit.inventory.ItemStack;
import static com.Acrobot.Breeze.Utils.MaterialUtil.getSignName;
import static com.Acrobot.ChestShop.Config.Property.GENERATE_STATISTICS_PAGE;
import static com.Acrobot.ChestShop.Config.Property.LOG_TO_DATABASE;
import static com.Acrobot.ChestShop.Events.TransactionEvent.Type.BUY;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.BUY;
/**
* @author Acrobot
@ -31,9 +31,11 @@ public class TransactionLogger implements Listener {
message.append(" sold ");
}
message.append(event.getItemAmount()).append(' ');
message.append(getSignName(event.getItem())).append(" for ");
message.append(event.getPrice());
for (ItemStack item : event.getStock()) {
message.append(item.getAmount()).append(' ').append(getSignName(item));
}
message.append(" for ").append(event.getPrice());
if (event.getTransactionType() == BUY) {
message.append(" from ");
@ -42,7 +44,6 @@ public class TransactionLogger implements Listener {
}
message.append(event.getOwner()).append(' ');
message.append(locationToString(event.getSign().getLocation()));
ChestShop.getBukkitLogger().info(message.toString());
@ -54,17 +55,19 @@ public class TransactionLogger implements Listener {
return;
}
Transaction transaction = new Transaction();
ItemStack item = event.getItem();
double pricePerStack = event.getPrice() / event.getStock().length;
transaction.setAmount(event.getItemAmount());
for (ItemStack item : event.getStock()) {
Transaction transaction = new Transaction();
transaction.setAmount(event.getStock()[0].getAmount());
transaction.setItemID(item.getTypeId());
transaction.setItemDurability(item.getDurability());
transaction.setPrice((float) event.getPrice());
transaction.setPrice((float) pricePerStack);
transaction.setShopOwner(event.getOwner());
transaction.setShopOwner(event.getOwner().getName());
transaction.setShopUser(event.getClient().getName());
transaction.setSec(System.currentTimeMillis() / 1000);
@ -72,6 +75,7 @@ public class TransactionLogger implements Listener {
Queue.addToQueue(transaction);
}
}
private static String locationToString(Location loc) {
return '[' + loc.getWorld().getName() + "] " + loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ();

View File

@ -1,6 +1,5 @@
package com.Acrobot.ChestShop.Listeners.Transaction;
package com.Acrobot.ChestShop.Listeners.Shop.PostTransaction;
import com.Acrobot.Breeze.Utils.StringUtil;
import com.Acrobot.ChestShop.Config.Config;
import com.Acrobot.ChestShop.Config.Language;
import com.Acrobot.ChestShop.Economy.Economy;
@ -10,6 +9,10 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
import static com.Acrobot.ChestShop.Config.Language.*;
import static com.Acrobot.ChestShop.Config.Property.SHOW_TRANSACTION_INFORMATION_CLIENT;
@ -21,7 +24,7 @@ import static com.Acrobot.ChestShop.Config.Property.SHOW_TRANSACTION_INFORMATION
public class TransactionMessageSender implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public static void onTransaction(TransactionEvent event) {
if (event.getTransactionType() == TransactionEvent.Type.BUY) {
if (event.getTransactionType() == TransactionEvent.TransactionType.BUY) {
sendBuyMessage(event);
} else {
sendSellMessage(event);
@ -29,23 +32,22 @@ public class TransactionMessageSender implements Listener {
}
protected static void sendBuyMessage(TransactionEvent event) {
String itemName = StringUtil.capitalizeFirstLetter(event.getItem().getType().name());
String owner = event.getOwner();
String itemName = parseItemInformation(event.getStock());
String owner = event.getOwner().getName();
Player player = event.getClient();
int amount = event.getItemAmount();
String price = Economy.formatBalance(event.getPrice());
if (Config.getBoolean(SHOW_TRANSACTION_INFORMATION_CLIENT)) {
String message = formatMessage(YOU_BOUGHT_FROM_SHOP, itemName, price, amount);
String message = formatMessage(YOU_BOUGHT_FROM_SHOP, itemName, price);
message = message.replace("%owner", owner);
player.sendMessage(message);
}
if (Config.getBoolean(SHOW_TRANSACTION_INFORMATION_OWNER)) {
String message = formatMessage(SOMEBODY_BOUGHT_FROM_YOUR_SHOP, itemName, price, amount);
String message = formatMessage(SOMEBODY_BOUGHT_FROM_YOUR_SHOP, itemName, price);
message = message.replace("%buyer", player.getName());
sendMessageToOwner(message, event);
@ -53,31 +55,54 @@ public class TransactionMessageSender implements Listener {
}
protected static void sendSellMessage(TransactionEvent event) {
String itemName = StringUtil.capitalizeFirstLetter(event.getItem().getType().name());
String owner = event.getOwner();
String itemName = parseItemInformation(event.getStock());
String owner = event.getOwner().getName();
Player player = event.getClient();
int amount = event.getItemAmount();
String price = Economy.formatBalance(event.getPrice());
if (Config.getBoolean(SHOW_TRANSACTION_INFORMATION_CLIENT)) {
String message = formatMessage(YOU_SOLD_TO_SHOP, itemName, price, amount);
String message = formatMessage(YOU_SOLD_TO_SHOP, itemName, price);
message = message.replace("%buyer", owner);
player.sendMessage(message);
}
if (Config.getBoolean(SHOW_TRANSACTION_INFORMATION_OWNER)) {
String message = formatMessage(SOMEBODY_SOLD_TO_YOUR_SHOP, itemName, price, amount);
String message = formatMessage(SOMEBODY_SOLD_TO_YOUR_SHOP, itemName, price);
message = message.replace("%seller", player.getName());
sendMessageToOwner(message, event);
}
}
private static String parseItemInformation(ItemStack[] items) {
Map<String, Integer> itemMap = new HashMap<String, Integer>();
for (ItemStack item : items) {
String matName = item.getType().name();
if (itemMap.containsKey(matName)) {
int curAmount = itemMap.get(matName);
itemMap.put(matName, curAmount + item.getAmount());
} else {
itemMap.put(matName, item.getAmount());
}
}
StringBuilder message = new StringBuilder(15);
for (Map.Entry<String, Integer> item : itemMap.entrySet()) {
message.append(item.getValue()).append(' ').append(item.getKey());
}
return message.toString();
}
private static void sendMessageToOwner(String message, TransactionEvent event) {
String owner = event.getOwner();
String owner = event.getOwner().getName();
Player player = Bukkit.getPlayer(owner);
@ -86,9 +111,8 @@ public class TransactionMessageSender implements Listener {
}
}
private static String formatMessage(Language message, String item, String price, int amount) {
private static String formatMessage(Language message, String item, String price) {
return Config.getLocal(message)
.replace("%amount", String.valueOf(amount))
.replace("%item", item)
.replace("%price", price);
}

View File

@ -0,0 +1,66 @@
package com.Acrobot.ChestShop.Listeners.Shop.PreTransaction;
import com.Acrobot.Breeze.Utils.InventoryUtil;
import com.Acrobot.ChestShop.Economy.Economy;
import com.Acrobot.ChestShop.Events.PreTransactionEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.*;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.BUY;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.SELL;
/**
* @author Acrobot
*/
public class AmountAndPriceChecker implements Listener {
@EventHandler
public static void onItemCheck(PreTransactionEvent event) {
if (event.isCancelled() || event.getTransactionType() != BUY) {
return;
}
ItemStack[] stock = event.getStock();
Inventory ownerInventory = event.getOwnerInventory();
if (!Economy.hasEnough(event.getClient().getName(), event.getPrice())) {
event.setCancelled(CLIENT_DOES_NOT_HAVE_ENOUGH_MONEY);
return;
}
if (!hasItems(ownerInventory, stock)) {
event.setCancelled(NOT_ENOUGH_STOCK_IN_CHEST);
}
}
@EventHandler
public static void onSellItemCheck(PreTransactionEvent event) {
if (event.isCancelled() || event.getTransactionType() != SELL) {
return;
}
ItemStack[] stock = event.getStock();
Inventory clientInventory = event.getClientInventory();
if (!Economy.hasEnough(event.getOwner().getName(), event.getPrice())) {
event.setCancelled(SHOP_DOES_NOT_HAVE_ENOUGH_MONEY);
return;
}
if (!hasItems(clientInventory, stock)) {
event.setCancelled(NOT_ENOUGH_STOCK_IN_INVENTORY);
}
}
private static boolean hasItems(Inventory inventory, ItemStack[] items) {
for (ItemStack item : items) {
if (InventoryUtil.getAmount(item, inventory) < item.getAmount()) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,27 @@
package com.Acrobot.ChestShop.Listeners.Shop.PreTransaction;
import com.Acrobot.ChestShop.Config.Config;
import com.Acrobot.ChestShop.Events.PreTransactionEvent;
import org.bukkit.GameMode;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import static com.Acrobot.ChestShop.Config.Property.IGNORE_CREATIVE_MODE;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.CREATIVE_MODE_PROTECTION;
/**
* @author Acrobot
*/
public class CreativeModeIgnorer implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public static void onPreTransaction(PreTransactionEvent event) {
if (event.isCancelled()) {
return;
}
if (Config.getBoolean(IGNORE_CREATIVE_MODE) && event.getClient().getGameMode() == GameMode.CREATIVE) {
event.setCancelled(CREATIVE_MODE_PROTECTION);
}
}
}

View File

@ -0,0 +1,73 @@
package com.Acrobot.ChestShop.Listeners.Shop.PreTransaction;
import com.Acrobot.ChestShop.Config.Config;
import com.Acrobot.ChestShop.Config.Language;
import com.Acrobot.ChestShop.Config.Property;
import com.Acrobot.ChestShop.Events.PreTransactionEvent;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
/**
* @author Acrobot
*/
public class ErrorMessageSender implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public static void onMessage(PreTransactionEvent event) {
if (!event.isCancelled()) {
return;
}
Language message = null;
switch(event.getTransactionOutcome()) {
case SHOP_DOES_NOT_BUY_THIS_ITEM:
message = Language.NO_BUYING_HERE;
break;
case SHOP_DOES_NOT_SELL_THIS_ITEM:
message = Language.NO_SELLING_HERE;
break;
case CLIENT_DOES_NOT_HAVE_PERMISSION:
message = Language.NO_PERMISSION;
break;
case CLIENT_DOES_NOT_HAVE_ENOUGH_MONEY:
message = Language.NOT_ENOUGH_MONEY;
break;
case SHOP_DOES_NOT_HAVE_ENOUGH_MONEY:
message = Language.NOT_ENOUGH_MONEY_SHOP;
break;
case NOT_ENOUGH_SPACE_IN_CHEST:
message = Language.NOT_ENOUGH_SPACE_IN_CHEST;
break;
case NOT_ENOUGH_SPACE_IN_INVENTORY:
message = Language.NOT_ENOUGH_SPACE_IN_INVENTORY;
break;
case NOT_ENOUGH_STOCK_IN_INVENTORY:
message = Language.NOT_ENOUGH_ITEMS_TO_SELL;
break;
case NOT_ENOUGH_STOCK_IN_CHEST:
sendMessageToOwner(event.getOwner(), Language.NOT_ENOUGH_STOCK_IN_YOUR_SHOP);
message = Language.NOT_ENOUGH_STOCK;
break;
case SHOP_IS_RESTRICTED:
message = Language.ACCESS_DENIED;
break;
case INVALID_SHOP:
message = Language.INVALID_SHOP_DETECTED;
break;
}
if (message != null) {
event.getClient().sendMessage(Config.getLocal(message));
}
}
private static void sendMessageToOwner(OfflinePlayer owner, Language message) {
if (owner.isOnline() && Config.getBoolean(Property.SHOW_MESSAGE_OUT_OF_STOCK)) {
Player player = (Player) owner;
player.sendMessage(Config.getLocal(message));
}
}
}

View File

@ -0,0 +1,189 @@
package com.Acrobot.ChestShop.Listeners.Shop.PreTransaction;
import com.Acrobot.Breeze.Utils.InventoryUtil;
import com.Acrobot.Breeze.Utils.MaterialUtil;
import com.Acrobot.ChestShop.Economy.Economy;
import com.Acrobot.ChestShop.Events.PreTransactionEvent;
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 java.util.LinkedList;
import java.util.List;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.*;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.BUY;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.SELL;
/**
* @author Acrobot
*/
public class PartialTransactionModule implements Listener {
@EventHandler(priority = EventPriority.LOW)
public static void onPreBuyTransaction(PreTransactionEvent event) {
if (event.isCancelled() || event.getTransactionType() != BUY) {
return;
}
Player client = event.getClient();
String clientName = client.getName();
ItemStack[] stock = event.getStock();
double price = event.getPrice();
double pricePerItem = event.getPrice() / getItemCount(stock);
double walletMoney = Economy.getBalance(clientName);
if (!Economy.hasEnough(clientName, price)) {
int amountAffordable = getAmountOfAffordableItems(walletMoney, pricePerItem);
if (amountAffordable < 1) {
event.setCancelled(CLIENT_DOES_NOT_HAVE_ENOUGH_MONEY);
return;
}
event.setPrice(amountAffordable * pricePerItem);
event.setStock(getCountedItemStack(stock, amountAffordable));
}
stock = event.getStock();
if (!hasItems(event.getOwnerInventory(), stock)) {
ItemStack[] itemsHad = getItems(stock, event.getOwnerInventory());
int posessedItemCount = getItemCount(itemsHad);
if (posessedItemCount <= 0) {
event.setCancelled(NOT_ENOUGH_STOCK_IN_CHEST);
return;
}
event.setPrice(pricePerItem * posessedItemCount);
event.setStock(itemsHad);
}
}
@EventHandler(priority = EventPriority.LOW)
public static void onPreSellTransaction(PreTransactionEvent event) {
if (event.isCancelled() || event.getTransactionType() != SELL) {
return;
}
String ownerName = event.getOwner().getName();
ItemStack[] stock = event.getStock();
double price = event.getPrice();
double pricePerItem = event.getPrice() / getItemCount(stock);
double walletMoney = Economy.getBalance(ownerName);
if (!Economy.hasEnough(ownerName, price)) {
int amountAffordable = getAmountOfAffordableItems(walletMoney, pricePerItem);
if (amountAffordable < 1) {
event.setCancelled(SHOP_DOES_NOT_HAVE_ENOUGH_MONEY);
return;
}
event.setPrice(amountAffordable * pricePerItem);
event.setStock(getCountedItemStack(stock, amountAffordable));
}
stock = event.getStock();
if (!hasItems(event.getClientInventory(), stock)) {
ItemStack[] itemsHad = getItems(stock, event.getClientInventory());
int posessedItemCount = getItemCount(itemsHad);
if (posessedItemCount <= 0) {
event.setCancelled(NOT_ENOUGH_STOCK_IN_INVENTORY);
return;
}
event.setPrice(pricePerItem * posessedItemCount);
event.setStock(itemsHad);
}
}
private static boolean hasItems(Inventory inventory, ItemStack[] items) {
for (ItemStack item : items) {
if (!inventory.contains(item, item.getAmount())) {
return false;
}
}
return true;
}
private static int getAmountOfAffordableItems(double walletMoney, double pricePerItem) {
return (int) Math.floor(walletMoney / pricePerItem);
}
private static int getItemCount(ItemStack[] items) {
int count = 0;
for (ItemStack item : items) {
count += item.getAmount();
}
return count;
}
private static ItemStack[] getItems(ItemStack[] stock, Inventory inventory) {
List<ItemStack> neededItems = new LinkedList<ItemStack>();
boolean itemAdded = false;
for (ItemStack item : stock) {
for (ItemStack needed : neededItems) {
if (MaterialUtil.equals(item, needed)) {
needed.setAmount(needed.getAmount() + item.getAmount());
itemAdded = true;
}
}
if (!itemAdded) {
neededItems.add(item);
itemAdded = false;
}
}
List<ItemStack> toReturn = new LinkedList<ItemStack>();
for (ItemStack item : neededItems) {
int amount = InventoryUtil.getAmount(item, inventory);
ItemStack clone = item.clone();
clone.setAmount(amount > item.getAmount() ? item.getAmount() : amount);
toReturn.add(clone);
}
return toReturn.toArray(stock);
}
private static ItemStack[] getCountedItemStack(ItemStack[] stock, int numberOfItems) {
int left = numberOfItems;
LinkedList<ItemStack> stacks = new LinkedList<ItemStack>();
for (ItemStack stack : stock) {
int count = stack.getAmount();
if (left > count) {
stacks.add(stack);
left -= count;
} else {
ItemStack clone = stack.clone();
clone.setAmount(left);
stacks.add(clone);
left = 0;
}
if (left <= 0) {
break;
}
}
return stacks.toArray(stock);
}
}

View File

@ -0,0 +1,44 @@
package com.Acrobot.ChestShop.Listeners.Shop.PreTransaction;
import com.Acrobot.ChestShop.Events.PreTransactionEvent;
import com.Acrobot.ChestShop.Events.TransactionEvent;
import com.Acrobot.ChestShop.Permission;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.CLIENT_DOES_NOT_HAVE_PERMISSION;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.BUY;
/**
* @author Acrobot
*/
public class PermissionChecker implements Listener {
@EventHandler
public static void onPermissionCheck(PreTransactionEvent event) {
if (event.isCancelled()) {
return;
}
Player client = event.getClient();
TransactionEvent.TransactionType transactionType = event.getTransactionType();
for (ItemStack stock : event.getStock()) {
String matID = Integer.toString(stock.getTypeId());
boolean hasPerm;
if (transactionType == BUY) {
hasPerm = Permission.has(client, Permission.BUY) || Permission.has(client, Permission.BUY_ID + matID);
} else {
hasPerm = Permission.has(client, Permission.SELL) || Permission.has(client, Permission.SELL_ID + matID);
}
if (!hasPerm) {
event.setCancelled(CLIENT_DOES_NOT_HAVE_PERMISSION);
return;
}
}
}
}

View File

@ -0,0 +1,34 @@
package com.Acrobot.ChestShop.Listeners.Shop.PreTransaction;
import com.Acrobot.Breeze.Utils.PriceUtil;
import com.Acrobot.ChestShop.Events.PreTransactionEvent;
import com.Acrobot.ChestShop.Events.TransactionEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.SHOP_DOES_NOT_BUY_THIS_ITEM;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.SHOP_DOES_NOT_SELL_THIS_ITEM;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.BUY;
/**
* @author Acrobot
*/
public class PriceValidator implements Listener {
@EventHandler
public static void onPriceCheck(PreTransactionEvent event) {
if (event.isCancelled()) {
return;
}
TransactionEvent.TransactionType transactionType = event.getTransactionType();
double price = event.getPrice();
if (price == PriceUtil.NO_PRICE) {
if (transactionType == BUY) {
event.setCancelled(SHOP_DOES_NOT_BUY_THIS_ITEM);
} else {
event.setCancelled(SHOP_DOES_NOT_SELL_THIS_ITEM);
}
}
}
}

View File

@ -0,0 +1,25 @@
package com.Acrobot.ChestShop.Listeners.Shop.PreTransaction;
import com.Acrobot.ChestShop.Events.PreTransactionEvent;
import com.Acrobot.ChestShop.Signs.ChestShopSign;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.INVALID_SHOP;
/**
* @author Acrobot
*/
public class ShopValidator implements Listener {
@EventHandler(priority = EventPriority.LOW)
public static void onCheck(PreTransactionEvent event) {
if (event.isCancelled()) {
return;
}
if (!ChestShopSign.isAdminShop(event.getSign()) && event.getOwnerInventory() == null) {
event.setCancelled(INVALID_SHOP);
}
}
}

View File

@ -0,0 +1,40 @@
package com.Acrobot.ChestShop.Listeners.Shop.PreTransaction;
import com.Acrobot.ChestShop.Events.PreTransactionEvent;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import java.util.Map;
import java.util.WeakHashMap;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.SPAM_CLICKING_PROTECTION;
/**
* @author Acrobot
*/
public class SpamClickProtector implements Listener {
private final Map<Player, Long> TIME_OF_LATEST_CLICK = new WeakHashMap<Player, Long>();
private final int interval;
public SpamClickProtector(int interval) {
this.interval = interval;
}
@EventHandler(priority = EventPriority.LOWEST)
public void onClick(PreTransactionEvent event) {
if (event.isCancelled()) {
return;
}
Player clicker = event.getClient();
if (TIME_OF_LATEST_CLICK.containsKey(clicker) && (System.currentTimeMillis() - TIME_OF_LATEST_CLICK.get(clicker)) < interval) {
event.setCancelled(SPAM_CLICKING_PROTECTION);
return;
}
TIME_OF_LATEST_CLICK.put(clicker, System.currentTimeMillis());
}
}

View File

@ -0,0 +1,56 @@
package com.Acrobot.ChestShop.Listeners.Shop.PreTransaction;
import com.Acrobot.Breeze.Utils.InventoryUtil;
import com.Acrobot.ChestShop.Events.PreTransactionEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.NOT_ENOUGH_SPACE_IN_CHEST;
import static com.Acrobot.ChestShop.Events.PreTransactionEvent.TransactionOutcome.NOT_ENOUGH_SPACE_IN_INVENTORY;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.BUY;
import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.SELL;
/**
* @author Acrobot
*/
public class StockFittingChecker implements Listener {
@EventHandler
public static void onSellCheck(PreTransactionEvent event) {
if (event.isCancelled() || event.getTransactionType() != SELL) {
return;
}
Inventory shopInventory = event.getOwnerInventory();
ItemStack[] stock = event.getStock();
if (!itemsFitInInventory(stock, shopInventory)) {
event.setCancelled(NOT_ENOUGH_SPACE_IN_CHEST);
}
}
@EventHandler
public static void onBuyCheck(PreTransactionEvent event) {
if (event.isCancelled() || event.getTransactionType() != BUY) {
return;
}
Inventory clientInventory = event.getClientInventory();
ItemStack[] stock = event.getStock();
if (!itemsFitInInventory(stock, clientInventory)) {
event.setCancelled(NOT_ENOUGH_SPACE_IN_INVENTORY);
}
}
private static boolean itemsFitInInventory(ItemStack[] items, Inventory inventory) {
for (ItemStack item : items) {
if (!InventoryUtil.fits(item, inventory)) {
return false;
}
}
return true;
}
}

View File

@ -1,35 +0,0 @@
package com.Acrobot.ChestShop.Listeners.Transaction;
import com.Acrobot.ChestShop.Config.Config;
import com.Acrobot.ChestShop.Config.Property;
import com.Acrobot.ChestShop.Containers.Container;
import com.Acrobot.ChestShop.Events.TransactionEvent;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
/**
* @author Acrobot
*/
public class EmptyShopDeleter implements Listener {
@EventHandler
public static void onTransaction(TransactionEvent event) {
if (event.getTransactionType() != TransactionEvent.Type.BUY) {
return;
}
if (shopShouldBeRemoved(event.getContainer())) {
event.getSign().getBlock().setType(Material.AIR);
event.getContainer().addItem(new ItemStack(Material.SIGN, 1));
}
}
private static boolean shopShouldBeRemoved(Container container) {
return Config.getBoolean(Property.REMOVE_EMPTY_SHOPS) && shopIsEmpty(container);
}
private static boolean shopIsEmpty(Container container) {
return container.isEmpty();
}
}