/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.internal.providers.kits; import com.jcwhatever.nucleus.Nucleus; import com.jcwhatever.nucleus.providers.kits.events.GiveKitEvent; import com.jcwhatever.nucleus.providers.kits.IKit; import com.jcwhatever.nucleus.providers.kits.IKitContext; import com.jcwhatever.nucleus.utils.ArrayUtils; import com.jcwhatever.nucleus.utils.PreCon; import com.jcwhatever.nucleus.managed.scheduler.Scheduler; import com.jcwhatever.nucleus.utils.inventory.InventoryUtils; import com.jcwhatever.nucleus.utils.items.ItemStackMatcher; import com.jcwhatever.nucleus.utils.materials.MaterialProperty; import com.jcwhatever.nucleus.utils.materials.Materials; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.annotation.Nullable; /** * Nucleus implementation of {@link IKit}. */ class NucleusKit implements IKit { private final Plugin _plugin; private final IKitContext _context; private final String _name; private final String _searchName; private ItemStack[] _armor = new ItemStack[4]; // helmet, chestplate, leggings, boots private List<ItemStack> _items; /** * Constructor. * * @param context The owning context. * @param name The name of the kit. */ public NucleusKit(IKitContext context, String name) { PreCon.notNull(context); PreCon.notNullOrEmpty(name); _plugin = context.getPlugin(); _context = context; _name = name; _searchName = name.toLowerCase(); _items = new ArrayList<ItemStack>(15); } @Override public Plugin getPlugin() { return _plugin; } @Override public String getName() { return _name; } @Override public String getSearchName() { return _searchName; } @Override public IKitContext getContext() { return _context; } @Override @Nullable public ItemStack getHelmet() { return _armor[0] != null ? _armor[0].clone() : null; } @Override @Nullable public ItemStack getChestplate() { return _armor[1] != null ? _armor[1].clone() : null; } @Override @Nullable public ItemStack getLeggings() { return _armor[2] != null ? _armor[2].clone() : null; } @Override @Nullable public ItemStack getBoots() { return _armor[3] != null ? _armor[3].clone() : null; } @Override public ItemStack[] getItems() { // deep clone into an array ItemStack[] array = new ItemStack[_items.size()]; for (int i = 0; i < _items.size(); ++i) { array[i] = _items.get(i).clone(); } return array; } @Override public ItemStack[] getArmor() { ItemStack[] armor = new ItemStack[4]; armor[0] = getHelmet(); armor[1] = getChestplate(); armor[2] = getLeggings(); armor[3] = getBoots(); return armor; } @Override public boolean take(Entity entity, int qty) { return take(entity, ItemStackMatcher.getDefault(), qty); } @Override public boolean take(Entity entity, ItemStackMatcher matcher, int qty) { PreCon.notNull(entity); PreCon.notNull(matcher); PreCon.greaterThanZero(qty); List<ItemStack> itemsToTake = new ArrayList<>(_items.size() + 4); itemsToTake.addAll(_items); if (_armor[0] != null) itemsToTake.add(getHelmet()); if (_armor[1] != null) itemsToTake.add(getChestplate()); if (_armor[2] != null) itemsToTake.add(getLeggings()); if (_armor[3] != null) itemsToTake.add(getBoots()); if (entity instanceof InventoryHolder) { InventoryHolder holder = (InventoryHolder)entity; // check entity has all required items for (ItemStack item : itemsToTake) { if (!InventoryUtils.has(holder.getInventory(), item, matcher, qty)) return false; } // take items for (ItemStack item : itemsToTake) { InventoryUtils.removeAmount(holder.getInventory(), item, matcher, qty); } return true; } return false; } @Override public void give(final Entity entity) { PreCon.notNull(entity); if (!(entity instanceof InventoryHolder) && !(entity instanceof LivingEntity)) return; final GiveKitEvent event = new GiveKitEvent(entity, NucleusKit.this); Nucleus.getEventManager().callBukkit(NucleusKit.this, event); if (event.isCancelled()) return; Scheduler.runTaskLater(_plugin, new Runnable() { @Override public void run() { Inventory inventory = entity instanceof InventoryHolder ? ((InventoryHolder) entity).getInventory() : null; EntityEquipment equipment = entity instanceof LivingEntity ? ((LivingEntity) entity).getEquipment() : null; // add items if (inventory != null) { for (ItemStack item : event.getItems()) { inventory.addItem(item); } } else if (equipment != null) { List<ItemStack> items = event.getItems(); if (items.size() > 0) equipment.setItemInHand(items.get(0)); } // add equipment if (equipment != null) { giveEquipment(equipment, event); } else if (inventory != null) { giveEquipmentInventory(inventory, event); } } }); } /** * Set the kits helmet item. * * @param helmet The helmet. */ protected void setHelmet(@Nullable ItemStack helmet) { _armor[0] = helmet != null ? helmet.clone() : null; } /** * Set the kits chest plate item. * * @param chestplate The chestplate. */ protected void setChestplate(@Nullable ItemStack chestplate) { _armor[1] = chestplate != null ? chestplate.clone() : null; } /** * Set the kits legging item. * * @param leggings The leggings. */ protected void setLeggings(@Nullable ItemStack leggings) { _armor[2] = leggings != null ? leggings.clone() : null; } /** * Set the kits boots item. * * @param boots The boots. */ protected void setBoots(@Nullable ItemStack boots) { _armor[3] = boots != null ? boots.clone() : null; } /** * Add an array of items, armor or non-armor, to the kit. * * <p>Armor items automatically replace the appropriate * armor item.</p> * * @param items The items to add. */ protected void addItems(ItemStack... items) { PreCon.notNull(items); InventoryUtils.add(_items, items); } /** * Add an array of items, armor or non-armor, to the kit. * * <p>Armor items automatically replace the appropriate * armor item.</p> * * @param items The items to add. */ protected void addItems(Collection<ItemStack> items) { PreCon.notNull(items); ItemStack[] itemArray = items.toArray(new ItemStack[items.size()]); InventoryUtils.add(_items, itemArray); } /** * Add a collection of items, armor or non-armor, to the kit. * * <p>Armor items automatically replace the appropriate * armor item.</p> * * @param items The items to add. */ protected void addAnyItems(ItemStack... items) { PreCon.notNull(items); List<ItemStack> clone = new ArrayList<>(items.length); Collections.addAll(clone, items); addAnyItems(clone); } /** * Add a collection of items, armor or non-armor, to the kit. * * <p>Armor items automatically replace the appropriate * armor item.</p> * * @param items The items to add. */ protected void addAnyItems(Collection<ItemStack> items) { PreCon.notNull(items); List<ItemStack> clone = new ArrayList<>(items); ItemStack helmet = null; ItemStack chestplate = null; ItemStack leggings = null; ItemStack boots = null; Iterator<ItemStack> iterator = clone.iterator(); while (iterator.hasNext()) { ItemStack item = iterator.next(); Set<MaterialProperty> properties = Materials.getProperties(item.getType()); if (properties.contains(MaterialProperty.ARMOR)) { if (properties.contains(MaterialProperty.HELMET)) { helmet = item; iterator.remove(); } else if (properties.contains(MaterialProperty.CHESTPLATE)) { chestplate = item; iterator.remove(); } else if (properties.contains(MaterialProperty.LEGGINGS)) { leggings = item; iterator.remove(); } else if (properties.contains(MaterialProperty.BOOTS)) { boots = item; iterator.remove(); } } if (helmet != null && chestplate != null && leggings != null && boots != null) break; } if (helmet != null) setHelmet(helmet); if (chestplate != null) setChestplate(chestplate); if (leggings != null) setLeggings(leggings); if (boots != null) setBoots(boots); if (!clone.isEmpty()) InventoryUtils.add(_items, clone.toArray(new ItemStack[clone.size()])); } /** * Remove an item from the kit, armor or non-armor. * * @param items The {@link ItemStack}'s to remove. * @return True if 1 or more items was removed, otherwise false. */ protected boolean removeItems(ItemStack... items) { PreCon.notNull(items); ItemStack[] kitItems = _items.toArray(new ItemStack[_items.size()]); if (!InventoryUtils.remove(kitItems, items).isEmpty()) { _items.clear(); kitItems = ArrayUtils.removeNull(kitItems); Collections.addAll(_items, kitItems); return true; } return false; } /** * Remove an item from the kit, armor or non-armor. * * @param items The {@link ItemStack}'s to remove. * * @return True if at least 1 of the items was found and removed, otherwise false. */ protected boolean removeAnyItems(ItemStack... items) { PreCon.notNull(items); List<ItemStack> clone = new ArrayList<>(items.length); Collections.addAll(clone, items); boolean[] armorFlags = new boolean[4]; Iterator<ItemStack> iterator = clone.iterator(); while (iterator.hasNext()) { ItemStack item = iterator.next(); Set<MaterialProperty> properties = Materials.getProperties(item.getType()); if (properties.contains(MaterialProperty.ARMOR)) { int index; if (properties.contains(MaterialProperty.HELMET)) { setHelmet(null); index = 0; } else if (properties.contains(MaterialProperty.CHESTPLATE)) { setChestplate(null); index = 1; } else if (properties.contains(MaterialProperty.LEGGINGS)) { setLeggings(null); index = 2; } else if (properties.contains(MaterialProperty.BOOTS)) { setBoots(null); index = 3; } else { continue; } armorFlags[index] = true; iterator.remove(); } if (armorFlags[0] && armorFlags[1] && armorFlags[2] && armorFlags[3]) break; } ItemStack[] kitItems = _items.toArray(new ItemStack[_items.size()]); if (!InventoryUtils.remove(kitItems, items).isEmpty()) { _items.clear(); kitItems = ArrayUtils.removeNull(kitItems); Collections.addAll(_items, kitItems); return true; } return false; } // give equipment to EntityEquipment private void giveEquipment(EntityEquipment equipment, GiveKitEvent event) { if (event.getHelmet() != null) equipment.setHelmet(event.getHelmet()); if (event.getChestplate() != null) equipment.setChestplate(event.getChestplate()); if (event.getLeggings() != null) equipment.setLeggings(event.getLeggings()); if (event.getBoots() != null) equipment.setBoots(event.getBoots()); } // give equipment to Inventory private void giveEquipmentInventory(Inventory inventory, GiveKitEvent event) { if (event.getHelmet() != null) inventory.addItem(event.getHelmet()); if (event.getChestplate() != null) inventory.addItem(event.getChestplate()); if (event.getLeggings() != null) inventory.addItem(event.getLeggings()); if (event.getBoots() != null) inventory.addItem(event.getBoots()); } }