Finish StackedItem manager

This commit is contained in:
ceze88 2023-05-30 11:20:31 +02:00
parent cef0ce7d33
commit c944e6add7
20 changed files with 572 additions and 305 deletions

View File

@ -5,7 +5,7 @@ import com.craftaro.ultimatestacker.api.stack.block.BlockStack;
import com.craftaro.ultimatestacker.api.stack.block.BlockStackManager;
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
import com.craftaro.ultimatestacker.api.stack.item.ItemStackManager;
import com.craftaro.ultimatestacker.api.stack.item.StackedItemManager;
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStack;
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStackManager;
import com.craftaro.ultimatestacker.commands.CommandConvert;
@ -32,10 +32,9 @@ import com.craftaro.ultimatestacker.lootables.LootablesManager;
import com.craftaro.ultimatestacker.stackable.block.BlockStackImpl;
import com.craftaro.ultimatestacker.stackable.entity.EntityStackManagerImpl;
import com.craftaro.ultimatestacker.stackable.entity.custom.CustomEntityManager;
import com.craftaro.ultimatestacker.stackable.item.ItemStackManagerImpl;
import com.craftaro.ultimatestacker.stackable.item.StackedItemManagerImpl;
import com.craftaro.ultimatestacker.stackable.spawner.SpawnerStackImpl;
import com.craftaro.ultimatestacker.utils.Async;
import com.craftaro.ultimatestacker.utils.Methods;
import com.songoda.core.SongodaCore;
import com.songoda.core.SongodaPlugin;
import com.songoda.core.commands.CommandManager;
@ -67,14 +66,10 @@ import com.craftaro.ultimatestacker.stackable.spawner.SpawnerStackManagerImpl;
import com.craftaro.ultimatestacker.tasks.StackingTask;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.PluginManager;
import java.util.ArrayList;
@ -98,7 +93,7 @@ public class UltimateStacker extends SongodaPlugin {
private EntityStackManager entityStackManager;
private SpawnerStackManager spawnerStackManager;
private BlockStackManager blockStackManager;
private ItemStackManager itemStackManager;
private StackedItemManager stackedItemManager;
private LootablesManager lootablesManager;
private CommandManager commandManager;
private CustomEntityManager customEntityManager;
@ -195,7 +190,7 @@ public class UltimateStacker extends SongodaPlugin {
this.spawnerStackManager = new SpawnerStackManagerImpl();
this.entityStackManager = new EntityStackManagerImpl(this);
this.blockStackManager = new BlockStackManagerImpl();
this.itemStackManager = new ItemStackManagerImpl();
this.stackedItemManager = new StackedItemManagerImpl();
this.customEntityManager = new CustomEntityManager();
guiManager.init();
@ -212,21 +207,24 @@ public class UltimateStacker extends SongodaPlugin {
pluginManager.registerEvents(new EntityListeners(this), this);
pluginManager.registerEvents(new ItemListeners(this), this);
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_12))
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_12)) {
pluginManager.registerEvents(new ItemCurrentListener(), this);
else
} else {
pluginManager.registerEvents(new ItemLegacyListener(), this);
}
pluginManager.registerEvents(new TameListeners(this), this);
pluginManager.registerEvents(new SpawnerListeners(this), this);
pluginManager.registerEvents(new SheepDyeListeners(this), this);
if (Settings.CLEAR_LAG.getBoolean() && pluginManager.isPluginEnabled("ClearLag"))
if (Settings.CLEAR_LAG.getBoolean() && pluginManager.isPluginEnabled("ClearLag")) {
pluginManager.registerEvents(new ClearLagListeners(this), this);
}
// Register Hooks
if (pluginManager.isPluginEnabled("Jobs"))
if (pluginManager.isPluginEnabled("Jobs")) {
stackerHooks.add(new JobsHook());
}
HologramManager.load(this);
EntityStackerManager.load();
@ -261,7 +259,7 @@ public class UltimateStacker extends SongodaPlugin {
new _6_RemoveStackedEntityTable());
this.dataMigrationManager.runMigrations();
API = new UltimateStackerAPI(entityStackManager, itemStackManager, spawnerStackManager, blockStackManager);
API = new UltimateStackerAPI(entityStackManager, stackedItemManager, spawnerStackManager, blockStackManager);
}
@Override
@ -384,8 +382,8 @@ public class UltimateStacker extends SongodaPlugin {
return entityStackManager;
}
public ItemStackManager getItemStackManager() {
return itemStackManager;
public StackedItemManager getStackedItemManager() {
return stackedItemManager;
}
public SpawnerStackManager getSpawnerStackManager() {
@ -420,118 +418,6 @@ public class UltimateStacker extends SongodaPlugin {
//////// Convenient API //////////
/**
* Spawn a stacked item at a location
*
* @param item The item to spawn
* @param amount The amount of items to spawn
* @param location The location to spawn the item
*/
public static void spawnStackedItem(ItemStack item, int amount, Location location) {
if (item.getType() == Material.AIR) return;
World world = location.getWorld();
if (world == null) return;
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_17)) {
world.dropItem(location, item, dropped -> {
if (dropped.getItemStack().getType() == Material.AIR) return;
updateItemMeta(dropped, item, amount);
});
} else {
Item dropped = world.dropItem(location, item);
if (dropped.getItemStack().getType() == Material.AIR) return;
updateItemMeta(dropped, item, amount);
}
}
/**
* Change the stacked amount for this item
*
* @param item item entity to update
* @param newAmount number of items this item represents
*/
public static void updateItemAmount(Item item, int newAmount) {
updateItemAmount(item, item.getItemStack(), newAmount);
}
/**
* Change the stacked amount for this item
*
* @param item item entity to update
* @param itemStack ItemStack that will represent this item
* @param newAmount number of items this item represents
*/
public static void updateItemAmount(Item item, ItemStack itemStack, int newAmount) {
boolean blacklisted = isMaterialBlacklisted(itemStack);
if (newAmount > (itemStack.getMaxStackSize() / 2) && !blacklisted)
itemStack.setAmount(Math.max(1, itemStack.getMaxStackSize() / 2));
else
itemStack.setAmount(newAmount);
// If amount is 0, Minecraft change the type to AIR
if (itemStack.getType() == Material.AIR)
return;
updateItemMeta(item, itemStack, newAmount);
}
public static void updateItemMeta(Item item, ItemStack itemStack, int newAmount) {
Material material = itemStack.getType();
if (material == Material.AIR)
return;
String name = TextUtils.convertToInvisibleString("IS") + Methods.compileItemName(itemStack, newAmount);
boolean blacklisted = isMaterialBlacklisted(itemStack);
if (newAmount > (itemStack.getMaxStackSize() / 2) && !blacklisted) {
item.setMetadata("US_AMT", new FixedMetadataValue(INSTANCE, newAmount));
} else {
item.removeMetadata("US_AMT", INSTANCE);
}
item.setItemStack(itemStack);
if ((blacklisted && !Settings.ITEM_HOLOGRAM_BLACKLIST.getBoolean())
|| !INSTANCE.getItemFile().getBoolean("Items." + material + ".Has Hologram")
|| !Settings.ITEM_HOLOGRAMS.getBoolean()
|| newAmount < Settings.ITEM_MIN_HOLOGRAM_SIZE.getInt())
return;
item.setCustomName(name);
item.setCustomNameVisible(true);
}
/**
* Lookup the stacked size of this item
*
* @param item item to check
* @return stacker-corrected value for the stack size
*/
public static int getActualItemAmount(Item item) {
ItemStack itemStack = item.getItemStack();
int amount = itemStack.getAmount();
if (/*amount >= (itemStack.getMaxStackSize() / 2) && */item.hasMetadata("US_AMT")) {
return item.getMetadata("US_AMT").get(0).asInt();
} else {
return amount;
}
}
/**
* Check to see if the amount stored in this itemstack is not the stacked
* amount
*
* @param item item to check
* @return true if Item.getItemStack().getAmount() is different from the
* stacked amount
*/
public static boolean hasCustomAmount(Item item) {
if (item.hasMetadata("US_AMT")) {
return item.getItemStack().getAmount() != item.getMetadata("US_AMT").get(0).asInt();
}
return false;
}
/**
* Check to see if this material is not permitted to stack
*

View File

@ -5,7 +5,6 @@ import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.core.utils.TextUtils;
import com.craftaro.ultimatestacker.UltimateStacker;
import com.craftaro.ultimatestacker.stackable.entity.EntityStackManagerImpl;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
@ -54,7 +53,7 @@ public class CommandRemoveAll extends AbstractCommand {
stack.destroy();
amountRemoved++;
} else if (entityO.getType() == EntityType.DROPPED_ITEM && type.equalsIgnoreCase("items")) {
if (!UltimateStacker.hasCustomAmount((Item)entityO) && !all)
if (!UltimateStacker.getInstance().getStackedItemManager().isStackedItem((Item)entityO) && !all)
continue;
entityO.remove();
amountRemoved++;

View File

@ -4,6 +4,7 @@ import com.craftaro.ultimatestacker.UltimateStacker;
import com.craftaro.ultimatestacker.api.UltimateStackerAPI;
import com.craftaro.ultimatestacker.api.stack.entity.EntityStack;
import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
import com.craftaro.ultimatestacker.api.stack.item.StackedItem;
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStack;
import com.craftaro.ultimatestacker.settings.Settings;
import com.craftaro.ultimatestacker.utils.Methods;
@ -70,8 +71,12 @@ public class EntityListeners implements Listener {
int amount = (stack.getAmount() - 1) + item.getAmount();
if (amount < 1) return;
item.setAmount(Math.min(amount, item.getMaxStackSize()));
if (amount > item.getMaxStackSize())
UltimateStacker.updateItemAmount(event.getEntity(), amount);
if (amount > item.getMaxStackSize()) {
StackedItem stackedItem = UltimateStackerAPI.getStackedItemManager().getStackedItem(event.getEntity());
if (stackedItem != null) {
stackedItem.setAmount(amount - item.getMaxStackSize());
}
}
event.getEntity().setItemStack(item);
}

View File

@ -1,5 +1,7 @@
package com.craftaro.ultimatestacker.listeners.item;
import com.craftaro.ultimatestacker.api.UltimateStackerAPI;
import com.craftaro.ultimatestacker.api.stack.item.StackedItem;
import com.songoda.core.compatibility.CompatibleSound;
import com.craftaro.ultimatestacker.UltimateStacker;
import com.craftaro.ultimatestacker.settings.Settings;
@ -20,9 +22,10 @@ public class ItemCurrentListener implements Listener {
// Amount here is not the total amount of item (32 if more than 32) but the amount of item the player can retrieve
// ie there is x64 diamonds blocks (so 32), the player pick 8 items so the amount is 8 and not 32
Item item = event.getItem();
ItemStack stack = item.getItemStack();
int amount = UltimateStacker.getActualItemAmount(item);
StackedItem stackedItem = UltimateStackerAPI.getStackedItemManager().getStackedItem(event.getItem());
if (stackedItem == null) return;
ItemStack stack = stackedItem.getItem().getItemStack();
int amount = stackedItem.getAmount();
if (event.getEntity() instanceof Player) {
if (amount < (stack.getMaxStackSize() / 2)) return;
@ -31,7 +34,7 @@ public class ItemCurrentListener implements Listener {
player.playSound(player.getLocation(), CompatibleSound.ENTITY_ITEM_PICKUP.getSound(), .2f, (float) (1 + Math.random()));
Methods.updateInventory(event.getItem(), player.getInventory());
} else {
UltimateStacker.updateItemMeta(item, stack, amount - 1);
stackedItem.setAmount(amount - 1);
}
}
}

View File

@ -1,5 +1,6 @@
package com.craftaro.ultimatestacker.listeners.item;
import com.craftaro.ultimatestacker.api.UltimateStackerAPI;
import com.songoda.core.compatibility.CompatibleSound;
import com.craftaro.ultimatestacker.UltimateStacker;
import com.craftaro.ultimatestacker.settings.Settings;
@ -13,6 +14,8 @@ import org.bukkit.inventory.ItemStack;
public class ItemLegacyListener implements Listener {
//TODO Do we need this?
@EventHandler
public void onPickup(PlayerPickupItemEvent event) {
if (!Settings.STACK_ITEMS.getBoolean() || event.getItem() instanceof Arrow) return;
@ -21,7 +24,7 @@ public class ItemLegacyListener implements Listener {
Item item = event.getItem();
ItemStack stack = item.getItemStack();
int amount = UltimateStacker.getActualItemAmount(item);
int amount = UltimateStackerAPI.getStackedItemManager().getActualItemAmount(item);
if (amount < (stack.getMaxStackSize() / 2)) return;
event.setCancelled(true);

View File

@ -1,5 +1,8 @@
package com.craftaro.ultimatestacker.listeners.item;
import com.craftaro.ultimatestacker.api.UltimateStackerAPI;
import com.craftaro.ultimatestacker.api.stack.item.StackedItem;
import com.craftaro.ultimatestacker.api.stack.item.StackedItemManager;
import com.songoda.core.nms.NmsManager;
import com.craftaro.ultimatestacker.UltimateStacker;
import com.craftaro.ultimatestacker.settings.Settings;
@ -7,7 +10,6 @@ import com.craftaro.ultimatestacker.utils.Methods;
import org.apache.commons.lang.StringUtils;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Item;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.ItemMergeEvent;
@ -30,37 +32,18 @@ public class ItemListeners implements Listener {
int maxItemStackSize = Settings.MAX_STACK_ITEMS.getInt();
if (!Settings.STACK_ITEMS.getBoolean()) return;
List<String> disabledWorlds = Settings.DISABLED_WORLDS.getStringList();
if (disabledWorlds.stream().anyMatch(worldStr -> event.getEntity().getWorld().getName().equalsIgnoreCase(worldStr)))
return;
Item item = event.getTarget();
ItemStack itemStack = item.getItemStack();
event.setCancelled(true);
int specific = plugin.getItemFile().getInt("Items." + itemStack.getType().name() + ".Max Stack Size");
int max;
if (UltimateStacker.isMaterialBlacklisted(itemStack))
max = new ItemStack(itemStack.getType()).getMaxStackSize();
else
max = specific == -1 && new ItemStack(itemStack.getType()).getMaxStackSize() != 1 ? maxItemStackSize : specific;
if (max == -1) max = 1;
int newAmount = UltimateStacker.getActualItemAmount(event.getEntity())
+ UltimateStacker.getActualItemAmount(item);
if (newAmount > max) return;
UltimateStacker.updateItemAmount(item, itemStack, newAmount);
event.getEntity().remove();
StackedItem stackedItem = UltimateStacker.getInstance().getStackedItemManager().merge(event.getEntity(), event.getTarget(), false, (fromStack, toStack, merged) -> {
if (fromStack == null && merged != null) {
//merge was successful
event.setCancelled(true);
event.getEntity().remove(); //remove the item that was merged
}
});
}
@EventHandler
public void onInvPickup(InventoryPickupItemEvent event) {
if (!Settings.STACK_ITEMS.getBoolean() || !UltimateStacker.hasCustomAmount(event.getItem())) {
if (!Settings.STACK_ITEMS.getBoolean() || !UltimateStacker.getInstance().getStackedItemManager().isStackedItem(event.getItem())) {
return;
}
@ -73,26 +56,32 @@ public class ItemListeners implements Listener {
}
}
@EventHandler
public void onExist(ItemSpawnEvent event) {
if (!Settings.STACK_ITEMS.getBoolean()) return;
//Do we need this?
List<String> disabledWorlds = Settings.DISABLED_WORLDS.getStringList();
if (disabledWorlds.stream().anyMatch(worldStr -> event.getEntity().getWorld().getName().equalsIgnoreCase(worldStr)))
return;
ItemStack itemStack = event.getEntity().getItemStack();
if (itemStack.hasItemMeta() && itemStack.getItemMeta().hasDisplayName() &&
StringUtils.substring(itemStack.getItemMeta().getDisplayName(), 0, 3).equals("***")) {
return; //Compatibility with Shop instance: https://www.spigotmc.org/resources/shop-a-simple-intuitive-shop-instance.9628/
}
if (UltimateStacker.hasCustomAmount(event.getEntity())) {
UltimateStacker.updateItemAmount(event.getEntity(), itemStack, UltimateStacker.getActualItemAmount(event.getEntity()) + itemStack.getAmount());
} else {
UltimateStacker.updateItemAmount(event.getEntity(), itemStack, itemStack.getAmount());
}
}
//@EventHandler
// public void onExist(ItemSpawnEvent event) {
// if (!Settings.STACK_ITEMS.getBoolean()) return;
//
// List<String> disabledWorlds = Settings.DISABLED_WORLDS.getStringList();
// if (disabledWorlds.stream().anyMatch(worldStr -> event.getEntity().getWorld().getName().equalsIgnoreCase(worldStr)))
// return;
//
// ItemStack itemStack = event.getEntity().getItemStack();
//
// if (itemStack.hasItemMeta() && itemStack.getItemMeta().hasDisplayName() &&
// StringUtils.substring(itemStack.getItemMeta().getDisplayName(), 0, 3).equals("***")) {
// return; //Compatibility with Shop instance: https://www.spigotmc.org/resources/shop-a-simple-intuitive-shop-instance.9628/
// }
//
// StackedItemManager itemStackManager = UltimateStackerAPI.getStackedItemManager();
//
// if (itemStackManager.isStackedItem(event.getEntity())) {
// StackedItem stackedItem = UltimateStacker.getInstance().getStackedItemManager().getStackedItem(event.getEntity());
// stackedItem.setAmount(stackedItem.getAmount() + itemStack.getAmount());
// UltimateStacker.updateItemAmount(event.getEntity(), itemStack, UltimateStacker.getActualItemAmount(event.getEntity()) + itemStack.getAmount());
// } else {
// UltimateStacker.updateItemAmount(event.getEntity(), itemStack, itemStack.getAmount());
// }
//
// }
}

View File

@ -1,10 +1,14 @@
package com.craftaro.ultimatestacker.stackable.block;
import com.craftaro.ultimatestacker.UltimateStacker;
import com.craftaro.ultimatestacker.api.stack.block.BlockStack;
import com.craftaro.ultimatestacker.api.stack.block.BlockStackManager;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
import java.util.Collection;
import java.util.Collections;
@ -15,43 +19,73 @@ public class BlockStackManagerImpl implements BlockStackManager {
private final Map<Location, BlockStack> registeredBlocks = new HashMap<>();
@Override
public void addBlocks(Map<Location, BlockStack> blocks) {
this.registeredBlocks.putAll(blocks);
}
@Override
public BlockStack addBlock(BlockStack blockStack) {
this.registeredBlocks.put(roundLocation(blockStack.getLocation()), blockStack);
return blockStack;
}
@Override
public BlockStack removeBlock(Location location) {
return registeredBlocks.remove(roundLocation(location));
}
@Override
public BlockStack getBlock(Location location) {
return this.registeredBlocks.get(location);
}
@Override
public BlockStack getBlock(Block block, CompatibleMaterial material) {
return this.getBlock(block.getLocation());
}
@Override
public BlockStack createBlock(Location location, CompatibleMaterial material) {
return this.registeredBlocks.computeIfAbsent(location, b -> new BlockStackImpl(material, location));
}
@Override
public BlockStack createBlock(Block block) {
return this.createBlock(block.getLocation(), CompatibleMaterial.getMaterial(block));
}
@Override
public boolean isBlock(Location location) {
return this.registeredBlocks.get(location) != null;
}
@Override
public Collection<BlockStack> getStacks() {
return Collections.unmodifiableCollection(this.registeredBlocks.values());
}
@Override
public boolean isMaterialBlacklisted(ItemStack item) {
return UltimateStacker.isMaterialBlacklisted(item);
}
@Override
public boolean isMaterialBlacklisted(String type) {
return UltimateStacker.isMaterialBlacklisted(type);
}
@Override
public boolean isMaterialBlacklisted(Material type) {
return UltimateStacker.isMaterialBlacklisted(type);
}
@Override
public boolean isMaterialBlacklisted(Material type, byte data) {
return UltimateStacker.isMaterialBlacklisted(type, data);
}
private Location roundLocation(Location location) {
location = location.clone();
location.setX(location.getBlockX());

View File

@ -1,35 +0,0 @@
package com.craftaro.ultimatestacker.stackable.item;
import com.craftaro.ultimatestacker.api.stack.item.ItemStack;
import com.songoda.core.compatibility.CompatibleMaterial;
import org.bukkit.entity.Item;
public class ItemStackImpl implements ItemStack {
private CompatibleMaterial material;
private Item item;
private int amount;
public ItemStackImpl() {
}
@Override
public int getAmount() {
return 0;
}
@Override
public void setAmount(int amount) {
}
@Override
public void add(int amount) {
}
@Override
public void take(int amount) {
}
}

View File

@ -1,18 +0,0 @@
package com.craftaro.ultimatestacker.stackable.item;
import com.craftaro.ultimatestacker.api.stack.item.ItemStack;
import com.craftaro.ultimatestacker.api.stack.item.ItemStackManager;
import org.bukkit.entity.Item;
public class ItemStackManagerImpl implements ItemStackManager {
@Override
public ItemStack getItem(Item item) {
return null;
}
@Override
public ItemStack createStack(Item item, int amount) {
return null;
}
}

View File

@ -0,0 +1,123 @@
package com.craftaro.ultimatestacker.stackable.item;
import com.craftaro.ultimatestacker.UltimateStacker;
import com.craftaro.ultimatestacker.api.stack.item.StackedItem;
import com.craftaro.ultimatestacker.settings.Settings;
import com.craftaro.ultimatestacker.utils.Methods;
import com.songoda.core.utils.TextUtils;
import org.bukkit.Material;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
public class StackedItemImpl implements StackedItem {
private final Item item;
public StackedItemImpl(Item item) {
this.item = item;
}
public StackedItemImpl(Item item, int amount) {
this.item = item;
setAmount(amount);
}
@Override
public int getAmount() {
ItemStack itemStack = item.getItemStack();
int amount = itemStack.getAmount();
if (item.hasMetadata("US_AMT")) {
return item.getMetadata("US_AMT").get(0).asInt();
} else {
return amount;
}
}
@Override
public void setAmount(int amount) {
updateItemAmount(item, amount);
}
@Override
public void add(int amount) {
updateItemAmount(item, getAmount() + amount);
}
@Override
public void take(int amount) {
//check that amount not go below 0
if (getAmount() - amount < 0) {
amount = 0;
}
updateItemAmount(item, getAmount() - amount);
}
private void updateItemAmount(Item item, int newAmount) {
updateItemAmount(item, item.getItemStack(), newAmount);
}
/**
* Change the stacked amount for this item
*
* @param item item entity to update
* @param itemStack StackedItem that will represent this item
* @param newAmount number of items this item represents
*/
private void updateItemAmount(Item item, ItemStack itemStack, int newAmount) {
boolean blacklisted = UltimateStacker.isMaterialBlacklisted(itemStack);
if (newAmount > (itemStack.getMaxStackSize() / 2) && !blacklisted) {
itemStack.setAmount(Math.max(1, itemStack.getMaxStackSize() / 2));
} else {
itemStack.setAmount(newAmount);
}
// If amount is 0, Minecraft change the type to AIR
if (itemStack.getType() == Material.AIR) {
return;
}
updateItemMeta(item, itemStack, newAmount);
}
private void updateItemMeta(Item item, ItemStack itemStack, int newAmount) {
Material material = itemStack.getType();
if (material == Material.AIR)
return;
String name = TextUtils.convertToInvisibleString("IS") + Methods.compileItemName(itemStack, newAmount);
boolean blacklisted = UltimateStacker.isMaterialBlacklisted(itemStack);
if (newAmount > (itemStack.getMaxStackSize() / 2) && !blacklisted) {
item.setMetadata("US_AMT", new FixedMetadataValue(UltimateStacker.getInstance(), newAmount));
} else {
item.removeMetadata("US_AMT", UltimateStacker.getInstance());
}
item.setItemStack(itemStack);
if ((blacklisted && !Settings.ITEM_HOLOGRAM_BLACKLIST.getBoolean())
|| !UltimateStacker.getInstance().getItemFile().getBoolean("Items." + material + ".Has Hologram")
|| !Settings.ITEM_HOLOGRAMS.getBoolean()
|| newAmount < Settings.ITEM_MIN_HOLOGRAM_SIZE.getInt())
return;
item.setCustomName(name);
item.setCustomNameVisible(true);
}
@Override
public Item getItem() {
return item;
}
@Override
public Item destroy() {
item.removeMetadata("US_AMT", UltimateStacker.getInstance());
item.setCustomName(null);
item.setCustomNameVisible(true);
return item;
}
}

View File

@ -0,0 +1,135 @@
package com.craftaro.ultimatestacker.stackable.item;
import com.craftaro.ultimatestacker.UltimateStacker;
import com.craftaro.ultimatestacker.api.stack.item.ItemMergeCallback;
import com.craftaro.ultimatestacker.api.stack.item.StackedItem;
import com.craftaro.ultimatestacker.api.stack.item.StackedItemManager;
import com.craftaro.ultimatestacker.settings.Settings;
import com.songoda.core.compatibility.ServerVersion;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
public class StackedItemManagerImpl implements StackedItemManager {
@Override
public @Nullable StackedItem getStackedItem(Item item) {
if (item.hasMetadata("US_AMT")) {
return new StackedItemImpl(item);
}
return null;
}
@Override
public @NotNull StackedItem getStackedItem(Item item, boolean create) {
return null;
}
@Override
public @Nullable StackedItem createStack(ItemStack item, Location location, int amount) {
if (item.getType() == Material.AIR) return null;
World world = location.getWorld();
if (world == null) return null;
AtomicReference<StackedItem> stack = new AtomicReference<>(null);
if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_17)) {
world.dropItem(location, item, dropped -> {
if (dropped.getItemStack().getType() == Material.AIR) return;
stack.set(new StackedItemImpl(dropped, amount));
});
} else {
Item dropped = world.dropItem(location, item);
if (dropped.getItemStack().getType() == Material.AIR) return null;
stack.set(new StackedItemImpl(dropped, amount));
}
return stack.get();
}
@Override
public @Nullable StackedItem createStack(Item item, int amount) {
return null;
}
@Override
public int getActualItemAmount(Item item) {
if (isStackedItem(item)) {
return item.getMetadata("US_AMT").get(0).asInt();
} else {
return item.getItemStack().getAmount();
}
}
@Override
public boolean isStackedItem(Item item) {
if (item.hasMetadata("US_AMT")) {
return item.getItemStack().getAmount() != item.getMetadata("US_AMT").get(0).asInt();
}
return false;
}
@Override
public StackedItem merge(Item from, Item to, boolean ignoreRestrictions) {
return merge(from, to, ignoreRestrictions, null);
}
@Override
public StackedItem merge(Item from, Item to, boolean ignoreRestrictions, ItemMergeCallback<Item, Item, StackedItem> callback) {
if (!ignoreRestrictions) {
if (!Settings.STACK_ITEMS.getBoolean()) return null;
List<String> disabledWorlds = Settings.DISABLED_WORLDS.getStringList();
if (disabledWorlds.stream().anyMatch(worldStr -> from.getWorld().getName().equalsIgnoreCase(worldStr))) {
return null;
}
}
int maxItemStackSize = Settings.MAX_STACK_ITEMS.getInt();
ItemStack fromItemStack = from.getItemStack();
ItemStack toItemStack = to.getItemStack();
if (fromItemStack.getType() != toItemStack.getType()) return null;
if (!ignoreRestrictions && UltimateStacker.isMaterialBlacklisted(fromItemStack)) return null;
int maxSize = UltimateStacker.getInstance().getItemFile().getInt("Items." + fromItemStack.getType().name() + ".Max Stack Size");
int fromAmount = getActualItemAmount(from);
int toAmount = getActualItemAmount(to);
if (fromAmount + toAmount > maxSize) {
if (callback != null) callback.accept(from, to, null);
//merge was unsuccessful
return null;
} else {
StackedItem merged = new StackedItemImpl(to, fromAmount + toAmount);
if (callback != null) callback.accept(null, to, merged);
return merged;
}
}
@Override
public boolean isMaterialBlacklisted(ItemStack item) {
return UltimateStacker.isMaterialBlacklisted(item);
}
@Override
public boolean isMaterialBlacklisted(String type) {
return UltimateStacker.isMaterialBlacklisted(type);
}
@Override
public boolean isMaterialBlacklisted(Material type) {
return UltimateStacker.isMaterialBlacklisted(type);
}
@Override
public boolean isMaterialBlacklisted(Material type, byte data) {
return UltimateStacker.isMaterialBlacklisted(type, data);
}
}

View File

@ -1,5 +1,7 @@
package com.craftaro.ultimatestacker.utils;
import com.craftaro.ultimatestacker.api.UltimateStackerAPI;
import com.craftaro.ultimatestacker.api.stack.item.StackedItem;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.third_party.de.tr7zw.nbtapi.NBTItem;
import com.songoda.core.utils.TextUtils;
@ -22,7 +24,8 @@ import java.util.Map;
public class Methods {
public static void updateInventory(Item item, Inventory inventory) {
int amount = UltimateStacker.getActualItemAmount(item);
StackedItem stackedItem = UltimateStackerAPI.getStackedItemManager().getStackedItem(item);
int amount = stackedItem.getAmount();
ItemStack itemStack = item.getItemStack();
final int maxStack = itemStack.getMaxStackSize();
@ -38,46 +41,11 @@ public class Methods {
}
}
if (amount <= 0)
if (amount <= 0) {
item.remove();
else
UltimateStacker.updateItemAmount(item, itemStack, amount);
}
// Do not touch! API for older plugins
@Deprecated
public static boolean isMaterialBlacklisted(Material type) {
return UltimateStacker.isMaterialBlacklisted(type);
}
// Do not touch! API for older plugins
@Deprecated
public static boolean isMaterialBlacklisted(Material type, byte data) {
return UltimateStacker.isMaterialBlacklisted(type, data);
}
// Do not touch! API for older plugins
@Deprecated
public static void updateItemAmount(Item item, int newAmount) {
UltimateStacker.updateItemAmount(item, newAmount);
}
// Do not touch! API for older plugins
@Deprecated
public static void updateItemAmount(Item item, ItemStack itemStack, int newAmount) {
UltimateStacker.updateItemAmount(item, itemStack, newAmount);
}
// Do not touch! API for older plugins
@Deprecated
public static int getActualItemAmount(Item item) {
return UltimateStacker.getActualItemAmount(item);
}
// Do not touch! API for older plugins
@Deprecated
public static boolean hasCustomAmount(Item item) {
return UltimateStacker.hasCustomAmount(item);
} else {
stackedItem.setAmount(amount);
}
}
public static String compileItemName(ItemStack item, int amount) {

View File

@ -74,5 +74,11 @@
<version>2.6.22</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>24.0.1</version>
</dependency>
</dependencies>
</project>

View File

@ -2,23 +2,23 @@ package com.craftaro.ultimatestacker.api;
import com.craftaro.ultimatestacker.api.stack.block.BlockStackManager;
import com.craftaro.ultimatestacker.api.stack.entity.EntityStackManager;
import com.craftaro.ultimatestacker.api.stack.item.ItemStackManager;
import com.craftaro.ultimatestacker.api.stack.item.StackedItemManager;
import com.craftaro.ultimatestacker.api.stack.spawner.SpawnerStackManager;
public final class UltimateStackerAPI {
private static EntityStackManager entityStackManager;
private static ItemStackManager itemStackManager;
private static StackedItemManager stackedItemManager;
private static SpawnerStackManager spawnerStackManager;
private static BlockStackManager blockStackManager;
private static UltimateStackerAPI instance;
public UltimateStackerAPI(EntityStackManager entityStackManager, ItemStackManager itemStackManager, SpawnerStackManager spawnerStackManager, BlockStackManager blockStackManager) {
if (UltimateStackerAPI.entityStackManager != null || UltimateStackerAPI.itemStackManager != null || UltimateStackerAPI.spawnerStackManager != null || UltimateStackerAPI.blockStackManager != null) {
public UltimateStackerAPI(EntityStackManager entityStackManager, StackedItemManager itemStackManager, SpawnerStackManager spawnerStackManager, BlockStackManager blockStackManager) {
if (UltimateStackerAPI.entityStackManager != null || UltimateStackerAPI.stackedItemManager != null || UltimateStackerAPI.spawnerStackManager != null || UltimateStackerAPI.blockStackManager != null) {
throw new IllegalStateException("UltimateStackerAPI has already been initialized!");
}
UltimateStackerAPI.entityStackManager = entityStackManager;
UltimateStackerAPI.itemStackManager = itemStackManager;
UltimateStackerAPI.stackedItemManager = itemStackManager;
UltimateStackerAPI.spawnerStackManager = spawnerStackManager;
UltimateStackerAPI.blockStackManager = blockStackManager;
instance = this;
@ -38,10 +38,10 @@ public final class UltimateStackerAPI {
/**
* Used to interact with ItemStacks
* @return The ItemStackManager
* @return The StackedItemManager
*/
public static ItemStackManager getItemStackManager() {
return itemStackManager;
public static StackedItemManager getStackedItemManager() {
return stackedItemManager;
}
/**
@ -52,6 +52,10 @@ public final class UltimateStackerAPI {
return spawnerStackManager;
}
/**
* Used to interact with BlockStacks
* @return The BlockStackManager
*/
public static BlockStackManager getBlockStackManager() {
return blockStackManager;
}

View File

@ -1,8 +1,11 @@
package com.craftaro.ultimatestacker.api.stack.block;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
import java.util.Collection;
import java.util.Map;
@ -26,4 +29,37 @@ public interface BlockStackManager {
boolean isBlock(Location location);
Collection<BlockStack> getStacks();
/**
* Check to see if this material is not permitted to stack
*
* @param item Item material to check
* @return true if this material will not stack
*/
boolean isMaterialBlacklisted(ItemStack item);
/**
* Check to see if this material is not permitted to stack
*
* @param type Material to check
* @return true if this material will not stack
*/
boolean isMaterialBlacklisted(String type);
/**
* Check to see if this material is not permitted to stack
*
* @param type Material to check
* @return true if this material will not stack
*/
boolean isMaterialBlacklisted(Material type);
/**
* Check to see if this material is not permitted to stack
*
* @param type Material to check
* @param data data value for this item (for 1.12 and older servers)
* @return true if this material will not stack
*/
boolean isMaterialBlacklisted(Material type, byte data);
}

View File

@ -0,0 +1,16 @@
package com.craftaro.ultimatestacker.api.stack.item;
import org.bukkit.entity.Item;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface ItemMergeCallback<F extends Item, T extends Item, S extends StackedItem> {
/**
* Called when two items are merged
* @param from The item that was merged into another (null if the merge was successful)
* @param to The item that was merged into
* @param stack The item that was created from the merge (null if the merge was unsuccessful)
*/
void accept(@Nullable F from, @NotNull T to, @Nullable S stack);
}

View File

@ -1,7 +0,0 @@
package com.craftaro.ultimatestacker.api.stack.item;
import com.craftaro.ultimatestacker.api.utils.StackableEntity;
public interface ItemStack extends StackableEntity {
}

View File

@ -1,11 +0,0 @@
package com.craftaro.ultimatestacker.api.stack.item;
import org.bukkit.entity.Item;
public interface ItemStackManager {
ItemStack getItem(Item item);
ItemStack createStack(Item item, int amount);
}

View File

@ -0,0 +1,20 @@
package com.craftaro.ultimatestacker.api.stack.item;
import com.craftaro.ultimatestacker.api.utils.StackableEntity;
import org.bukkit.entity.Item;
public interface StackedItem extends StackableEntity {
/**
* Get the Item entity for this StackedItem
* @return The Item entity for this StackedItem
*/
Item getItem();
/**
* Removes the custom amount from the item
* while not destroying the actual item
*/
Item destroy();
}

View File

@ -0,0 +1,111 @@
package com.craftaro.ultimatestacker.api.stack.item;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Item;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface StackedItemManager {
/**
* Get the StackedItem for the given Item
* @param item The Item to get the stack for
* @return The StackedItem for the given Item or null if not stacked
*/
@Nullable StackedItem getStackedItem(Item item);
/**
* Get the StackedItem for the given Item
* @param item The Item to get the stack for
* @param create If true, will create a new stack if one does not exist
* @return The StackedItem for the given Item or null if not stacked
*/
@NotNull StackedItem getStackedItem(Item item, boolean create);
/**
* Create a new StackedItem for the given item
* @param item The ItemStack to create the stack for
* @param amount The amount of items in the stack
* @param location The location to spawn the stack
* @return The StackedItem for the given Item or null if it could not be created
*/
@Nullable StackedItem createStack(ItemStack item, Location location, int amount);
/**
* Create a new StackedItem for the given item
* @param item The item to create the stack for
* @param amount The amount of items in the stack
* @return The StackedItem for the given Item or null if it could not be created
*/
@Nullable StackedItem createStack(Item item, int amount);
/**
* Get the actual amount of the given item
* @param item item to check
* @return The amount of items in the stacked item or vanilla stack size if not stacked
*/
int getActualItemAmount(Item item);
/**
* Returns true if the given item is stacked
*
* @param item item to check
* @return true if the given item is stacked
*/
boolean isStackedItem(Item item);
/**
* Merge two items together if they are the same type
* @param from first item
* @param to second item
* @param ignoreRestrictions ignore ignoreRestrictions such as max stack size, or blacklist
* @return The merged item or null if they merge was unsuccessful
*/
StackedItem merge(Item from, Item to, boolean ignoreRestrictions);
/**
* Merge two items together if they are the same type
* @param from first item
* @param to second item
* @param ignoreRestrictions ignore ignoreRestrictions such as max stack size, or blacklist
* @param callback callback to be called when the merge is successful see {@link ItemMergeCallback#accept(Item, Item, StackedItem)}
* @return The merged item or null if they merge was unsuccessful
*/
StackedItem merge(Item from, Item to, boolean ignoreRestrictions, ItemMergeCallback<Item, Item, StackedItem> callback);
/**
* Check to see if this material is not permitted to stack
*
* @param item Item material to check
* @return true if this material will not stack
*/
boolean isMaterialBlacklisted(ItemStack item);
/**
* Check to see if this material is not permitted to stack
*
* @param type Material to check
* @return true if this material will not stack
*/
boolean isMaterialBlacklisted(String type);
/**
* Check to see if this material is not permitted to stack
*
* @param type Material to check
* @return true if this material will not stack
*/
boolean isMaterialBlacklisted(Material type);
/**
* Check to see if this material is not permitted to stack
*
* @param type Material to check
* @param data data value for this item (for 1.12 and older servers)
* @return true if this material will not stack
*/
boolean isMaterialBlacklisted(Material type, byte data);
}