Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions plugin/src/main/java/com/Acrobot/ChestShop/ChestShop.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.Acrobot.ChestShop.Configuration.Messages;
import com.Acrobot.ChestShop.Configuration.Properties;
import com.Acrobot.ChestShop.Database.Migrations;
import com.Acrobot.ChestShop.Events.StockUpdateEvent;
import com.Acrobot.ChestShop.Listeners.Block.BlockPlace;
import com.Acrobot.ChestShop.Listeners.Block.Break.ChestBreak;
import com.Acrobot.ChestShop.Listeners.Block.Break.SignBreak;
Expand Down Expand Up @@ -41,6 +42,7 @@
import com.Acrobot.ChestShop.Listeners.PreTransaction.PermissionChecker;
import com.Acrobot.ChestShop.Listeners.ShopRemoval.ShopRefundListener;
import com.Acrobot.ChestShop.Listeners.ShopRemoval.ShopRemovalLogger;
import com.Acrobot.ChestShop.Listeners.StockUpdateListener;
import com.Acrobot.ChestShop.Logging.FileFormatter;
import com.Acrobot.ChestShop.Metadata.ItemDatabase;
import com.Acrobot.ChestShop.Signs.RestrictedSign;
Expand All @@ -53,7 +55,6 @@
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;

import com.google.common.reflect.ClassPath;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
Expand Down Expand Up @@ -372,9 +373,12 @@ private void registerEvents() {

registerEvent(new RestrictedSign());

if (!Properties.TURN_OFF_HOPPER_PROTECTION || Properties.USE_STOCK_COUNTER) {
registerEvent(new ItemMoveListener());
if (Properties.USE_STOCK_COUNTER) {
registerEvent(new StockUpdateListener());
}

// Register after init, so that we can check if someone is listening.
getServer().getScheduler().runTask(this, this::registerStockListeners);
}

private void registerShopRemovalEvents() {
Expand Down Expand Up @@ -435,7 +439,6 @@ private void registerModules() {
registerEvent(new DiscountModule());
registerEvent(new MetricsModule());
registerEvent(new PriceRestrictionModule());
registerEvent(new StockCounterModule());

registerEconomicalModules();
}
Expand All @@ -445,6 +448,15 @@ private void registerEconomicalModules() {
registerEvent(new TaxModule());
}

private void registerStockListeners() {
if ( StockUpdateEvent.hasHandlers()) {
registerEvent(new ItemMoveListener());
registerEvent(new StockCounterModule());
} else if ( !Properties.TURN_OFF_HOPPER_PROTECTION ) {
registerEvent(new ItemMoveListener());
}
}

private void registerVersionedAdapters() {
// Search jar file for version adapters
try (JarFile jarFile = new JarFile(this.getFile())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.Acrobot.ChestShop.Events;

import org.bukkit.block.Sign;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;

/**
* Represents a state after a shop's stock changes
*
* @author bjorn-out
*/
public class StockUpdateEvent extends Event {
private static final HandlerList handlers = new HandlerList();

private final int stock;
private final Sign sign;

public StockUpdateEvent(int stock, Sign sign) {
this.stock = stock;
this.sign = sign;
}

/**
* @return Stock available (number of items)
*/
public int getStock() {
return stock;
}

/**
* @return Shop's sign
*/
public Sign getSign() {
return sign;
}

public static HandlerList getHandlerList() {
return handlers;
}

public static boolean hasHandlers() {
return handlers.getRegisteredListeners().length > 0;
}

@Override
@NotNull
public HandlerList getHandlers() {
return handlers;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.Acrobot.ChestShop.Listeners.Item;

import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Configuration.Properties;
import com.Acrobot.ChestShop.Listeners.Modules.StockCounterModule;
import com.Acrobot.ChestShop.Events.StockUpdateEvent;
import com.Acrobot.ChestShop.Signs.ChestShopSign;
import org.bukkit.Bukkit;
import org.bukkit.block.BlockState;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
Expand All @@ -11,6 +13,7 @@
import org.bukkit.inventory.InventoryHolder;

import static com.Acrobot.Breeze.Utils.ImplementationAdapter.getHolder;
import static com.Acrobot.ChestShop.Listeners.Modules.StockCounterModule.fireStockUpdateEvents;

/**
* @author Acrobot
Expand All @@ -28,8 +31,10 @@ public static void onItemMove(InventoryMoveItemEvent event) {
return;
}
}
if (Properties.USE_STOCK_COUNTER && ChestShopSign.isShopBlock(destinationHolder)) {
StockCounterModule.updateCounterOnItemMoveEvent(event.getItem(), destinationHolder);

if (StockUpdateEvent.hasHandlers() && ChestShopSign.isShopBlock(destinationHolder)) {
Bukkit.getScheduler().runTask(ChestShop.getPlugin(), () ->
fireStockUpdateEvents(event.getDestination()));
Comment on lines +36 to +37
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably directly fire the event, not schedule a task as InventoryMoveItemEvents can occur very frequently and spamming new tasks every time this interact with a shop container seems ill-adviced. (Also I don't see why this should be delayed a tick when it worked without a delay previously already)

}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package com.Acrobot.ChestShop.Listeners.Modules;

import com.Acrobot.Breeze.Utils.InventoryUtil;
import com.Acrobot.Breeze.Utils.MaterialUtil;
import com.Acrobot.Breeze.Utils.QuantityUtil;
import com.Acrobot.ChestShop.ChestShop;
import com.Acrobot.ChestShop.Configuration.Properties;
import com.Acrobot.ChestShop.Events.ItemParseEvent;
import com.Acrobot.ChestShop.Events.PreShopCreationEvent;
import com.Acrobot.ChestShop.Events.StockUpdateEvent;
import com.Acrobot.ChestShop.Events.TransactionEvent;
import com.Acrobot.ChestShop.Signs.ChestShopSign;
import com.Acrobot.ChestShop.Utils.uBlock;
import org.bukkit.Bukkit;
import org.bukkit.block.Block;
import org.bukkit.block.Container;
import org.bukkit.block.Sign;
import org.bukkit.event.EventHandler;
Expand All @@ -23,165 +20,55 @@
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;

import java.util.IllegalFormatException;

import static com.Acrobot.Breeze.Utils.ImplementationAdapter.getHolder;
import static com.Acrobot.ChestShop.Signs.ChestShopSign.QUANTITY_LINE;
import static org.bukkit.Bukkit.getServer;


/**
* @author bricefrisco
*/
public class StockCounterModule implements Listener {
private static final String PRICE_LINE_WITH_COUNT = "Q %d : C %d";

@EventHandler(priority = EventPriority.HIGH)
public static void onPreShopCreation(PreShopCreationEvent event) {
int quantity;
try {
quantity = ChestShopSign.getQuantity(event.getSignLines());
} catch (IllegalArgumentException invalidQuantity) {
return;
}

if (QuantityUtil.quantityLineContainsCounter(ChestShopSign.getQuantityLine(event.getSignLines()))) {
event.setSignLine(QUANTITY_LINE, Integer.toString(quantity));
}

if (!Properties.USE_STOCK_COUNTER
|| (Properties.FORCE_UNLIMITED_ADMIN_SHOP && ChestShopSign.isAdminShop(event.getSignLines()))) {
return;
}
if (!StockUpdateEvent.hasHandlers()) { return; }
Container container = uBlock.findConnectedContainer(event.getSign());
if (container == null) { return; }

if (Properties.MAX_SHOP_AMOUNT > 99999) {
ChestShop.getBukkitLogger().warning("Stock counter cannot be used if MAX_SHOP_AMOUNT is over 5 digits");
return;
}

ItemStack itemTradedByShop = determineItemTradedByShop(ChestShopSign.getItem(event.getSignLines()));
if (itemTradedByShop != null) {
Container container = uBlock.findConnectedContainer(event.getSign());
if (container != null) {
event.setSignLine(QUANTITY_LINE, getQuantityLineWithCounter(quantity, itemTradedByShop, container.getInventory()));
}
}
Bukkit.getScheduler().runTask(ChestShop.getPlugin(), () ->
fireStockUpdateEvents(container.getInventory()));
}

@EventHandler
@EventHandler(priority = EventPriority.MONITOR)
public static void onInventoryClose(InventoryCloseEvent event) {
if (!StockUpdateEvent.hasHandlers()) { return; }

if (event.getInventory().getType() == InventoryType.ENDER_CHEST || event.getInventory().getLocation() == null) {
return;
}

InventoryHolder holder = getHolder(event.getInventory(), false);
if (!uBlock.couldBeShopContainer(holder)) {
return;
}

for (Sign shopSign : uBlock.findConnectedShopSigns(holder)) {
if (!Properties.USE_STOCK_COUNTER
|| (Properties.FORCE_UNLIMITED_ADMIN_SHOP && ChestShopSign.isAdminShop(shopSign))) {
if (QuantityUtil.quantityLineContainsCounter(ChestShopSign.getQuantityLine(shopSign))) {
removeCounterFromQuantityLine(shopSign);
}
continue;
}

if (Properties.MAX_SHOP_AMOUNT > 99999) {
ChestShop.getBukkitLogger().warning("Stock counter cannot be used if MAX_SHOP_AMOUNT is over 5 digits");
if (QuantityUtil.quantityLineContainsCounter(ChestShopSign.getQuantityLine(shopSign))) {
removeCounterFromQuantityLine(shopSign);
}
return;
}
if (!uBlock.couldBeShopContainer(holder)) { return; }

updateCounterOnQuantityLine(shopSign, event.getInventory());
}
fireStockUpdateEvents(event.getInventory());
}

@EventHandler(priority = EventPriority.HIGH)
@EventHandler(priority = EventPriority.MONITOR)
public static void onTransaction(final TransactionEvent event) {
String quantityLine = ChestShopSign.getQuantityLine(event.getSign());
if (!Properties.USE_STOCK_COUNTER) {
if (QuantityUtil.quantityLineContainsCounter(quantityLine)) {
removeCounterFromQuantityLine(event.getSign());
}
return;
}

if (Properties.MAX_SHOP_AMOUNT > 99999) {
ChestShop.getBukkitLogger().warning("Stock counter cannot be used if MAX_SHOP_AMOUNT is over 5 digits");
if (QuantityUtil.quantityLineContainsCounter(quantityLine)) {
removeCounterFromQuantityLine(event.getSign());
}
return;
}

if (Properties.FORCE_UNLIMITED_ADMIN_SHOP && ChestShopSign.isAdminShop(event.getSign())) {
return;
}

for (Sign shopSign : uBlock.findConnectedShopSigns( getHolder(event.getOwnerInventory(), false))) {
updateCounterOnQuantityLine(shopSign, event.getOwnerInventory());
}
if (!StockUpdateEvent.hasHandlers()) { return; }
fireStockUpdateEvents(event.getOwnerInventory());
}

/**
* Update the stock counter on the sign's quantity line
* @param sign The sign to update
* @param chestShopInventory The inventory to search in
* @param extraItems The extra items to add in the search
*/
public static void updateCounterOnQuantityLine(Sign sign, Inventory chestShopInventory, ItemStack... extraItems) {
ItemStack itemTradedByShop = determineItemTradedByShop(sign);
if (itemTradedByShop == null) {
return;
}

int quantity;
try {
quantity = ChestShopSign.getQuantity(sign);
} catch (IllegalFormatException invalidQuantity) {
return;
}

int numTradedItemsInChest = InventoryUtil.getAmount(itemTradedByShop, chestShopInventory);

for (ItemStack extraStack : extraItems) {
if (!MaterialUtil.equals(extraStack, itemTradedByShop)) {
continue;
public static void fireStockUpdateEvents(Inventory inventory) {
for (Sign sign : uBlock.findConnectedShopSigns( getHolder(inventory, false))) {
ItemStack itemTradedByShop = determineItemTradedByShop(sign);
if (itemTradedByShop == null) {
return;
}
int stock = InventoryUtil.getAmount(itemTradedByShop, inventory);

numTradedItemsInChest += extraStack.getAmount();
}

sign.setLine(QUANTITY_LINE, String.format(PRICE_LINE_WITH_COUNT, quantity, numTradedItemsInChest));
sign.update(true);
}

public static void updateCounterOnItemMoveEvent(ItemStack toAdd, InventoryHolder destinationHolder) {
Block shopBlock = ChestShopSign.getShopBlock(destinationHolder);
Sign connectedSign = uBlock.getConnectedSign(shopBlock);

updateCounterOnQuantityLine(connectedSign, destinationHolder.getInventory(), toAdd);
}

public static void removeCounterFromQuantityLine(Sign sign) {
int quantity;
try {
quantity = ChestShopSign.getQuantity(sign);
} catch (IllegalFormatException invalidQuantity) {
return;
StockUpdateEvent updateEvent = new StockUpdateEvent(stock, sign);
getServer().getPluginManager().callEvent(updateEvent);
}

sign.setLine(QUANTITY_LINE, Integer.toString(quantity));
sign.update(true);
}

public static String getQuantityLineWithCounter(int amount, ItemStack itemTransacted, Inventory chestShopInventory) {
int numTransactionItemsInChest = InventoryUtil.getAmount(itemTransacted, chestShopInventory);

return String.format(PRICE_LINE_WITH_COUNT, amount, numTransactionItemsInChest);
}

public static ItemStack determineItemTradedByShop(Sign sign) {
Expand Down
Loading