mirror of
https://github.com/ChestShop-authors/ChestShop-3.git
synced 2024-11-27 04:25:14 +01:00
Allow partial transactions due to missing inventory space (Fixes #88)
This commit is contained in:
parent
a0505e995e
commit
b23a0d238e
@ -74,6 +74,23 @@ public class InventoryUtil {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count amount of empty slots in an inventory
|
||||
*
|
||||
* @param inventory the inventory
|
||||
* @return The amount of empty slots
|
||||
*/
|
||||
public static int countEmpty(Inventory inventory) {
|
||||
int emptyAmount = 0;
|
||||
for (ItemStack stack : getStorageContents(inventory)) {
|
||||
if (MaterialUtil.isEmpty(stack)) {
|
||||
emptyAmount++;
|
||||
}
|
||||
}
|
||||
|
||||
return emptyAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the inventory has stock of this type
|
||||
@ -92,6 +109,24 @@ public class InventoryUtil {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if items fit in the inventory
|
||||
*
|
||||
* @param items Items to check
|
||||
* @param inventory inventory
|
||||
* @return Do the items fit inside the inventory?
|
||||
*/
|
||||
public static boolean fits(ItemStack[] items, Inventory inventory) {
|
||||
ItemStack[] mergedItems = InventoryUtil.mergeSimilarStacks(items);
|
||||
for (ItemStack item : mergedItems) {
|
||||
if (!InventoryUtil.fits(item, inventory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the item fits the inventory
|
||||
|
@ -70,7 +70,7 @@ public class Properties {
|
||||
@ConfigurationComment("Do you want to allow other players to build a shop on a block where there's one already?")
|
||||
public static boolean ALLOW_MULTIPLE_SHOPS_AT_ONE_BLOCK = false;
|
||||
|
||||
@ConfigurationComment("Can shops be used even when the seller doesn't have enough items? (The price will be scaled adequately to the item amount)")
|
||||
@ConfigurationComment("Can shops be used even when the buyer/seller doesn't have enough items, space or money? (The price will be scaled adequately to the item amount)")
|
||||
public static boolean ALLOW_PARTIAL_TRANSACTIONS = true;
|
||||
|
||||
@ConfigurationComment("Can '?' be put in place of item name in order for the sign to be auto-filled?")
|
||||
|
@ -16,6 +16,7 @@ import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@ -29,24 +30,22 @@ import static com.Acrobot.ChestShop.Events.TransactionEvent.TransactionType.SELL
|
||||
*/
|
||||
public class PartialTransactionModule implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public static void onPreBuyTransaction(PreTransactionEvent event) {
|
||||
if (event.isCancelled() || event.getTransactionType() != BUY) {
|
||||
if (event.getTransactionType() != BUY) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player client = event.getClient();
|
||||
ItemStack[] stock = event.getStock();
|
||||
|
||||
double price = event.getPrice();
|
||||
double pricePerItem = event.getPrice() / InventoryUtil.countItems(stock);
|
||||
double pricePerItem = event.getPrice() / InventoryUtil.countItems(event.getStock());
|
||||
|
||||
CurrencyAmountEvent currencyAmountEvent = new CurrencyAmountEvent(client);
|
||||
ChestShop.callEvent(currencyAmountEvent);
|
||||
|
||||
BigDecimal walletMoney = currencyAmountEvent.getAmount();
|
||||
|
||||
CurrencyCheckEvent currencyCheckEvent = new CurrencyCheckEvent(BigDecimal.valueOf(price), client);
|
||||
CurrencyCheckEvent currencyCheckEvent = new CurrencyCheckEvent(BigDecimal.valueOf(event.getPrice()), client);
|
||||
ChestShop.callEvent(currencyCheckEvent);
|
||||
|
||||
if (!currencyCheckEvent.hasEnough()) {
|
||||
@ -58,47 +57,54 @@ public class PartialTransactionModule implements Listener {
|
||||
}
|
||||
|
||||
event.setPrice(amountAffordable * pricePerItem);
|
||||
event.setStock(getCountedItemStack(stock, amountAffordable));
|
||||
event.setStock(getCountedItemStack(event.getStock(), amountAffordable));
|
||||
}
|
||||
|
||||
if (!InventoryUtil.hasItems(event.getStock(), event.getOwnerInventory())) {
|
||||
ItemStack[] itemsHad = getItems(event.getStock(), event.getOwnerInventory());
|
||||
int possessedItemCount = InventoryUtil.countItems(itemsHad);
|
||||
|
||||
if (possessedItemCount <= 0) {
|
||||
event.setCancelled(NOT_ENOUGH_STOCK_IN_CHEST);
|
||||
return;
|
||||
}
|
||||
|
||||
event.setPrice(pricePerItem * possessedItemCount);
|
||||
event.setStock(itemsHad);
|
||||
}
|
||||
|
||||
if (!InventoryUtil.fits(event.getStock(), event.getClientInventory())) {
|
||||
ItemStack[] itemsFit = getItemsThatFit(event.getStock(), event.getClientInventory());
|
||||
int possessedItemCount = InventoryUtil.countItems(itemsFit);
|
||||
if (possessedItemCount <= 0) {
|
||||
event.setCancelled(NOT_ENOUGH_SPACE_IN_INVENTORY);
|
||||
return;
|
||||
}
|
||||
|
||||
event.setStock(itemsFit);
|
||||
event.setPrice(pricePerItem * possessedItemCount);
|
||||
}
|
||||
|
||||
UUID seller = event.getOwnerAccount().getUuid();
|
||||
|
||||
UUID seller = event.getOwner().getUniqueId();
|
||||
|
||||
CurrencyHoldEvent currencyHoldEvent = new CurrencyHoldEvent(BigDecimal.valueOf(price), seller, client.getWorld());
|
||||
CurrencyHoldEvent currencyHoldEvent = new CurrencyHoldEvent(BigDecimal.valueOf(event.getPrice()), seller, client.getWorld());
|
||||
ChestShop.callEvent(currencyHoldEvent);
|
||||
|
||||
if (!currencyHoldEvent.canHold()) {
|
||||
event.setCancelled(SHOP_DEPOSIT_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
stock = event.getStock();
|
||||
|
||||
if (!InventoryUtil.hasItems(stock, event.getOwnerInventory())) {
|
||||
ItemStack[] itemsHad = getItems(stock, event.getOwnerInventory());
|
||||
int posessedItemCount = InventoryUtil.countItems(itemsHad);
|
||||
|
||||
if (posessedItemCount <= 0) {
|
||||
event.setCancelled(NOT_ENOUGH_STOCK_IN_CHEST);
|
||||
return;
|
||||
}
|
||||
|
||||
event.setPrice(pricePerItem * posessedItemCount);
|
||||
event.setStock(itemsHad);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||
public static void onPreSellTransaction(PreTransactionEvent event) {
|
||||
if (event.isCancelled() || event.getTransactionType() != SELL) {
|
||||
if (event.getTransactionType() != SELL) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player client = event.getClient();
|
||||
UUID owner = event.getOwner().getUniqueId();
|
||||
ItemStack[] stock = event.getStock();
|
||||
UUID owner = event.getOwnerAccount().getUuid();
|
||||
|
||||
double price = event.getPrice();
|
||||
double pricePerItem = event.getPrice() / InventoryUtil.countItems(stock);
|
||||
double pricePerItem = event.getPrice() / InventoryUtil.countItems(event.getStock());
|
||||
|
||||
CurrencyAmountEvent currencyAmountEvent = new CurrencyAmountEvent(owner, client.getWorld());
|
||||
ChestShop.callEvent(currencyAmountEvent);
|
||||
@ -106,7 +112,7 @@ public class PartialTransactionModule implements Listener {
|
||||
BigDecimal walletMoney = currencyAmountEvent.getAmount();
|
||||
|
||||
if (Economy.isOwnerEconomicallyActive(event.getOwnerInventory())) {
|
||||
CurrencyCheckEvent currencyCheckEvent = new CurrencyCheckEvent(BigDecimal.valueOf(price), owner, client.getWorld());
|
||||
CurrencyCheckEvent currencyCheckEvent = new CurrencyCheckEvent(BigDecimal.valueOf(event.getPrice()), owner, client.getWorld());
|
||||
ChestShop.callEvent(currencyCheckEvent);
|
||||
|
||||
if (!currencyCheckEvent.hasEnough()) {
|
||||
@ -118,31 +124,40 @@ public class PartialTransactionModule implements Listener {
|
||||
}
|
||||
|
||||
event.setPrice(amountAffordable * pricePerItem);
|
||||
event.setStock(getCountedItemStack(stock, amountAffordable));
|
||||
event.setStock(getCountedItemStack(event.getStock(), amountAffordable));
|
||||
}
|
||||
}
|
||||
|
||||
if (!InventoryUtil.hasItems(event.getStock(), event.getClientInventory())) {
|
||||
ItemStack[] itemsHad = getItems(event.getStock(), event.getClientInventory());
|
||||
int possessedItemCount = InventoryUtil.countItems(itemsHad);
|
||||
|
||||
if (possessedItemCount <= 0) {
|
||||
event.setCancelled(NOT_ENOUGH_STOCK_IN_INVENTORY);
|
||||
return;
|
||||
}
|
||||
|
||||
event.setPrice(pricePerItem * possessedItemCount);
|
||||
event.setStock(itemsHad);
|
||||
}
|
||||
|
||||
if (!InventoryUtil.fits(event.getStock(), event.getOwnerInventory())) {
|
||||
ItemStack[] itemsFit = getItemsThatFit(event.getStock(), event.getOwnerInventory());
|
||||
int possessedItemCount = InventoryUtil.countItems(itemsFit);
|
||||
if (possessedItemCount <= 0) {
|
||||
event.setCancelled(NOT_ENOUGH_STOCK_IN_CHEST);
|
||||
return;
|
||||
}
|
||||
|
||||
event.setStock(itemsFit);
|
||||
event.setPrice(pricePerItem * possessedItemCount);
|
||||
}
|
||||
|
||||
stock = event.getStock();
|
||||
|
||||
CurrencyHoldEvent currencyHoldEvent = new CurrencyHoldEvent(BigDecimal.valueOf(price), client);
|
||||
CurrencyHoldEvent currencyHoldEvent = new CurrencyHoldEvent(BigDecimal.valueOf(event.getPrice()), client);
|
||||
ChestShop.callEvent(currencyHoldEvent);
|
||||
|
||||
if (!currencyHoldEvent.canHold()) {
|
||||
event.setCancelled(CLIENT_DEPOSIT_FAILED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!InventoryUtil.hasItems(stock, event.getClientInventory())) {
|
||||
ItemStack[] itemsHad = getItems(stock, event.getClientInventory());
|
||||
int posessedItemCount = InventoryUtil.countItems(itemsHad);
|
||||
|
||||
if (posessedItemCount <= 0) {
|
||||
event.setCancelled(NOT_ENOUGH_STOCK_IN_INVENTORY);
|
||||
return;
|
||||
}
|
||||
|
||||
event.setPrice(pricePerItem * posessedItemCount);
|
||||
event.setStock(itemsHad);
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,4 +222,51 @@ public class PartialTransactionModule implements Listener {
|
||||
|
||||
return stacks.toArray(new ItemStack[stacks.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an array of items fit into an inventory.
|
||||
*
|
||||
* @param stock The items to fit in the inventory
|
||||
* @param inventory The inventory to fit it in
|
||||
* @return Whether or not the items fit into the inventory
|
||||
*/
|
||||
private static ItemStack[] getItemsThatFit(ItemStack[] stock, Inventory inventory) {
|
||||
List<ItemStack> resultStock = new ArrayList<>();
|
||||
|
||||
int emptySlots = InventoryUtil.countEmpty(inventory);
|
||||
ItemStack[] itemsInInventory = getItems(stock, inventory);
|
||||
|
||||
for (ItemStack item : stock) {
|
||||
int maxStackSize = InventoryUtil.getMaxStackSize(item);
|
||||
int free = 0;
|
||||
for (ItemStack itemInInventory : itemsInInventory) {
|
||||
if (MaterialUtil.equals(item, itemInInventory)) {
|
||||
free = (maxStackSize - itemInInventory.getAmount()) % maxStackSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (free == 0 && emptySlots == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemStack clone = item.clone();
|
||||
if (item.getAmount() > free) {
|
||||
if (emptySlots > 0) {
|
||||
int requiredSlots = (int) Math.ceil((item.getAmount() - free) / maxStackSize);
|
||||
if (requiredSlots <= emptySlots) {
|
||||
emptySlots = emptySlots - requiredSlots;
|
||||
} else {
|
||||
emptySlots = 0;
|
||||
clone.setAmount(free + maxStackSize * emptySlots);
|
||||
}
|
||||
} else {
|
||||
clone.setAmount(free);
|
||||
}
|
||||
}
|
||||
resultStock.add(clone);
|
||||
}
|
||||
|
||||
return (ItemStack[]) resultStock.toArray();
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ public class StockFittingChecker implements Listener {
|
||||
Inventory shopInventory = event.getOwnerInventory();
|
||||
ItemStack[] stock = event.getStock();
|
||||
|
||||
if (!itemsFitInInventory(stock, shopInventory)) {
|
||||
if (!InventoryUtil.fits(stock, shopInventory)) {
|
||||
event.setCancelled(NOT_ENOUGH_SPACE_IN_CHEST);
|
||||
}
|
||||
}
|
||||
@ -40,19 +40,8 @@ public class StockFittingChecker implements Listener {
|
||||
Inventory clientInventory = event.getClientInventory();
|
||||
ItemStack[] stock = event.getStock();
|
||||
|
||||
if (!itemsFitInInventory(stock, clientInventory)) {
|
||||
if (!InventoryUtil.fits(stock, clientInventory)) {
|
||||
event.setCancelled(NOT_ENOUGH_SPACE_IN_INVENTORY);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean itemsFitInInventory(ItemStack[] items, Inventory inventory) {
|
||||
ItemStack[] mergedItems = InventoryUtil.mergeSimilarStacks(items);
|
||||
for (ItemStack item : mergedItems) {
|
||||
if (!InventoryUtil.fits(item, inventory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user