diff --git a/Essentials/src/main/java/com/earth2me/essentials/Kit.java b/Essentials/src/main/java/com/earth2me/essentials/Kit.java index 322fad65f..30a0996f8 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Kit.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Kit.java @@ -26,6 +26,7 @@ import java.util.GregorianCalendar; import java.util.List; import java.util.Map; import java.util.logging.Level; +import java.util.stream.Collectors; import static com.earth2me.essentials.I18n.tlLiteral; @@ -127,10 +128,10 @@ public class Kit { @Deprecated public List getItems(final User user) throws Exception { - return getItems(); + return getBasicItems(); } - public List getItems() throws Exception { + public List getBasicItems() throws Exception { if (kit == null) { throw new TranslatableException("kitNotFound"); } @@ -154,14 +155,46 @@ public class Kit { } } - public boolean expandItems(final User user) throws Exception { - return expandItems(user, getItems(user)); + public List getGearItems() throws Exception { + if (kit == null) { + throw new TranslatableException("kitNotFound"); + } + try { + final List itemList = new ArrayList<>(); + final String[] gearConfigName = {"boots", "leggings", "chestplate", "helmet", "offhand"}; + for (String itemName : gearConfigName) { + final Object item = kit.get(itemName); + if (item == null) { + itemList.add(null); + continue; + } + + if (item instanceof String) { + itemList.add(item.toString()); + continue; + } + throw new Exception("Invalid kit item: " + item.toString()); + } + + return itemList; + } catch (final Exception e) { + ess.getLogger().log(Level.WARNING, "Error parsing kit " + kitName + ": " + e.getMessage()); + throw new TranslatableException(e,"kitError2"); + } } - public boolean expandItems(final User user, final List items) throws Exception { + public boolean expandItems(final User user) throws Exception { + return expandItems(user, getItems(user), getGearItems()); + } + + public boolean expandItems(final User user, final List items, final List gearItems) throws Exception { try { - final IText input = new SimpleTextInput(items); - final IText output = new KeywordReplacer(input, user.getSource(), ess, true, true); + final IText basicInput = new SimpleTextInput(items); + final IText basicOutput = new KeywordReplacer(basicInput, user.getSource(), ess, true, true); + + final List nonNullGearItems = gearItems.stream().filter(is -> is != null).collect(Collectors.toList()); + final IText gearInput = new SimpleTextInput(nonNullGearItems); + final IText gearOutput = new KeywordReplacer(gearInput, user.getSource(), ess, true, true); final KitClaimEvent event = new KitClaimEvent(user, this); Bukkit.getPluginManager().callEvent(event); @@ -173,58 +206,29 @@ public class Kit { final boolean allowUnsafe = ess.getSettings().allowUnsafeEnchantments(); final boolean autoEquip = ess.getSettings().isKitAutoEquip(); final List itemList = new ArrayList<>(); + final List gearList = new ArrayList<>(); final List commandQueue = new ArrayList<>(); final List moneyQueue = new ArrayList<>(); final String currencySymbol = ess.getSettings().getCurrencySymbol().isEmpty() ? "$" : ess.getSettings().getCurrencySymbol(); - for (final String kitItem : output.getLines()) { - if (kitItem.startsWith("$") || kitItem.startsWith(currencySymbol)) { - moneyQueue.add(NumberUtil.sanitizeCurrencyString(kitItem, ess)); - continue; - } - if (kitItem.startsWith("/")) { - String command = kitItem.substring(1); - final String name = user.getName(); - command = command.replace("{player}", name); - commandQueue.add(command); - continue; - } - - final ItemStack stack; - - if (kitItem.startsWith("@")) { - if (ess.getSerializationProvider() == null) { - ess.getLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("kitError3", kitName, user.getName()))); - continue; - } - stack = ess.getSerializationProvider().deserializeItem(Base64Coder.decodeLines(kitItem.substring(1))); - } else { - final String[] parts = kitItem.split(" +"); - final ItemStack parseStack = ess.getItemDb().get(parts[0], parts.length > 1 ? Integer.parseInt(parts[1]) : 1); - - if (parseStack.getType() == Material.AIR) { - continue; - } - - final MetaItemStack metaStack = new MetaItemStack(parseStack); - - if (parts.length > 2) { - // We pass a null sender here because kits should not do perm checks - metaStack.parseStringMeta(null, allowUnsafe, parts, 2, ess); - } - - stack = metaStack.getItemStack(); - } - - itemList.add(stack); - } + populateKitLists(user, basicOutput, moneyQueue, commandQueue, itemList, allowUnsafe, currencySymbol); + populateKitLists(user, gearOutput, moneyQueue, commandQueue, gearList, allowUnsafe, currencySymbol); final int maxStackSize = user.isAuthorized("essentials.oversizedstacks") ? ess.getSettings().getOversizedStackSize() : 0; final boolean isDropItemsIfFull = ess.getSettings().isDropItemsIfFull(); - final KitPreExpandItemsEvent itemsEvent = new KitPreExpandItemsEvent(user, kitName, itemList); + final List totalItems = new ArrayList<>(itemList); + totalItems.addAll(gearList.stream().filter(is -> is != null).collect(Collectors.toList())); + final KitPreExpandItemsEvent itemsEvent = new KitPreExpandItemsEvent(user, kitName, totalItems); Bukkit.getPluginManager().callEvent(itemsEvent); + final List nullGearItemsIndexes = findNullIndexes(gearItems); + + final ItemStack[] gearArray = addNullIndexes(gearList, nullGearItemsIndexes).toArray(new ItemStack[0]); + final List leftovers = Inventories.addGear(user.getBase(), gearArray); + + itemList.addAll(leftovers); + final ItemStack[] itemArray = itemList.toArray(new ItemStack[0]); if (!isDropItemsIfFull && !Inventories.hasSpace(user.getBase(), maxStackSize, autoEquip, itemArray)) { @@ -274,4 +278,76 @@ public class Kit { } return true; } + + private void populateKitLists(User user, IText output, List moneyQueue, List commandQueue, List itemList, boolean allowUnsafe, String currencySymbol) throws Exception { + for (final String kitItem : output.getLines()) { + if (kitItem.startsWith(currencySymbol)) { + moneyQueue.add(NumberUtil.sanitizeCurrencyString(kitItem, ess)); + continue; + } + + if (kitItem.startsWith("/")) { + String command = kitItem.substring(1); + final String name = user.getName(); + command = command.replace("{player}", name); + commandQueue.add(command); + continue; + } + + final ItemStack stack = parseItemStack(kitItem, user, allowUnsafe); + if (stack == null) { + continue; + } + + itemList.add(stack); + } + } + + private ItemStack parseItemStack(String kitItem, User user, boolean allowUnsafe) throws Exception { + if (kitItem.startsWith("@")) { + if (ess.getSerializationProvider() == null) { + ess.getLogger().log(Level.WARNING, AdventureUtil.miniToLegacy(tlLiteral("kitError3", kitName, user.getName()))); + return null; + } + return ess.getSerializationProvider().deserializeItem(Base64Coder.decodeLines(kitItem.substring(1))); + } else { + final String[] parts = kitItem.split(" +"); + final ItemStack parseStack = ess.getItemDb().get(parts[0], parts.length > 1 ? Integer.parseInt(parts[1]) : 1); + + if (parseStack.getType() == Material.AIR) { + return null; + } + + final MetaItemStack metaStack = new MetaItemStack(parseStack); + + if (parts.length > 2) { + // We pass a null sender here because kits should not do perm checks + metaStack.parseStringMeta(null, allowUnsafe, parts, 2, ess); + } + + return metaStack.getItemStack(); + } + } + + private List findNullIndexes(List list) { + final List nullIndexes = new ArrayList<>(); + + for (int i = 0; i < list.size(); i++) { + if (list.get(i) == null) { + nullIndexes.add(i); + } + } + + return nullIndexes; + } + + private List addNullIndexes(List list, List nullIndexes) { + final List newList = new ArrayList<>(list); + + for (int nullIndex : nullIndexes) { + newList.add(nullIndex, null); + } + + return newList; + } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/Kits.java b/Essentials/src/main/java/com/earth2me/essentials/Kits.java index 6cdafb9de..d71c1adc5 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Kits.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Kits.java @@ -112,11 +112,20 @@ public class Kits implements IConf { return null; } - public void addKit(String name, final List lines, final long delay) { + public void addKit(String name, final List basicLines, final List gearLines, final long delay) { name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH); // Will overwrite but w/e rootConfig.setProperty("kits." + name + ".delay", delay); - rootConfig.setProperty("kits." + name + ".items", lines); + rootConfig.setProperty("kits." + name + ".items", basicLines); + + final String[] gearConfigName = {"boots", "leggings", "chestplate", "helmet", "offhand"}; + for (int i = 0; i < gearLines.size(); i++) { + final String gearLine = gearLines.get(i); + if (gearLine != null) { + rootConfig.setProperty("kits." + name + "." + gearConfigName[i], gearLine); + } + } + parseKits(); rootConfig.save(); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandcreatekit.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandcreatekit.java index eda36424c..71a79d9a1 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandcreatekit.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandcreatekit.java @@ -39,8 +39,10 @@ public class Commandcreatekit extends EssentialsCommand { // Command handler will auto fail if this fails. final long delay = Long.parseLong(args[1]); final String kitname = args[0]; - final ItemStack[] items = Inventories.getInventory(user.getBase(), true); + final ItemStack[] items = Inventories.getInventoryBasicContents(user.getBase()); + final ItemStack[] gear = Inventories.getInventoryGear(user.getBase()); final List list = new ArrayList<>(); + final List gearList = new ArrayList<>(); boolean useSerializationProvider = ess.getSettings().isUseBetterKits(); @@ -50,26 +52,43 @@ public class Commandcreatekit extends EssentialsCommand { } for (ItemStack is : items) { - if (is != null && is.getType() != null && is.getType() != Material.AIR) { - final String serialized; - if (useSerializationProvider) { - serialized = "@" + Base64Coder.encodeLines(ess.getSerializationProvider().serializeItem(is)); - } else { - serialized = ess.getItemDb().serialize(is); - } + final String serialized = serializeItem(is, useSerializationProvider); + if (serialized != null) { list.add(serialized); } } + + int gearItemsAmount = 0; + for (ItemStack is : gear) { + gearItemsAmount = is == null ? gearItemsAmount : gearItemsAmount + 1; + gearList.add(serializeItem(is, useSerializationProvider)); + } + // Some users might want to directly write to config knowing the consequences. *shrug* if (!ess.getSettings().isPastebinCreateKit()) { - ess.getKits().addKit(kitname, list, delay); - user.sendTl("createdKit", kitname, list.size(), delay); + ess.getKits().addKit(kitname, list, gearList, delay); + user.sendTl("createdKit", kitname, list.size() + gearItemsAmount, delay); } else { - uploadPaste(user.getSource(), kitname, delay, list); + uploadPaste(user.getSource(), kitname, delay, list, gearList); } } - private void uploadPaste(final CommandSource sender, final String kitName, final long delay, final List list) { + private String serializeItem(ItemStack is, boolean useSerializationProvider) { + if (is != null && is.getType() != null && is.getType() != Material.AIR) { + final String serialized; + if (useSerializationProvider) { + serialized = "@" + Base64Coder.encodeLines(ess.getSerializationProvider().serializeItem(is)); + } else { + serialized = ess.getItemDb().serialize(is); + } + + return serialized; + } + + return null; + } + + private void uploadPaste(final CommandSource sender, final String kitName, final long delay, final List list, final List gearList) { ess.runTaskAsynchronously(() -> { try { final StringWriter sw = new StringWriter(); @@ -79,6 +98,14 @@ public class Commandcreatekit extends EssentialsCommand { config.node("kits", kitName, "delay").set(delay); config.node("kits", kitName, "items").set(list); + final String[] gearConfigName = {"boots", "leggings", "chestplate", "helmet", "offhand"}; + for (int i = 0; i < gearList.size(); i++) { + final String gearLine = gearList.get(i); + if (gearLine != null) { + config.node("kits", kitName, gearConfigName[i]).set(gearList.get(i)); + } + } + sw.append("# Copy the kit code below into the kits section in your config.yml file\n"); loader.save(config); diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandshowkit.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandshowkit.java index feca5d54c..60226893c 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandshowkit.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandshowkit.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.stream.Collectors; public class Commandshowkit extends EssentialsCommand { public Commandshowkit() { @@ -22,7 +23,11 @@ public class Commandshowkit extends EssentialsCommand { for (final String kitName : args[0].toLowerCase(Locale.ENGLISH).split(",")) { user.sendTl("kitContains", kitName); - for (final String s : new Kit(kitName, ess).getItems()) { + final Kit kit = new Kit(kitName, ess); + for (final String s : kit.getBasicItems()) { + user.sendTl("kitItem", s); + } + for (final String s : kit.getGearItems().stream().filter(is -> is != null).collect(Collectors.toList())) { user.sendTl("kitItem", s); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/craftbukkit/Inventories.java b/Essentials/src/main/java/com/earth2me/essentials/craftbukkit/Inventories.java index eb5c395bf..77d0b4146 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/craftbukkit/Inventories.java +++ b/Essentials/src/main/java/com/earth2me/essentials/craftbukkit/Inventories.java @@ -21,6 +21,7 @@ public final class Inventories { private static final int BOOT_SLOT = 36; private static final boolean HAS_OFFHAND = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_9_R01); private static final int INVENTORY_SIZE = HAS_OFFHAND ? 41 : 40; + private static final int BASIC_INVENTORY_SIZE = 36; private Inventories() { } @@ -132,6 +133,24 @@ public final class Inventories { return true; } + public static List addGear(final Player player, final ItemStack... items) { + final List leftovers = new ArrayList<>(); + + for (int i = 0; i < items.length; i++) { + if (items[i] != null) { + final ItemStack playerCurrentGear = player.getInventory().getItem(BASIC_INVENTORY_SIZE + i); + + if (!isEmpty(playerCurrentGear)) { + leftovers.add(items[i]); + } + + player.getInventory().setItem(BASIC_INVENTORY_SIZE + i, items[i]); + } + } + + return leftovers; + } + public static Map addItem(final Player player, final ItemStack... items) { return addItem(player, 0, false, items); } @@ -212,6 +231,24 @@ public final class Inventories { return items; } + public static ItemStack[] getInventoryBasicContents(final Player player) { + final ItemStack[] items = new ItemStack[BASIC_INVENTORY_SIZE]; + for (int i = 0; i < items.length; i++) { + items[i] = player.getInventory().getItem(i); + } + + return items; + } + + public static ItemStack[] getInventoryGear(final Player player) { + final ItemStack[] items = new ItemStack[INVENTORY_SIZE - BASIC_INVENTORY_SIZE]; + for (int i = 0; i < items.length; i++) { + items[i] = player.getInventory().getItem(BASIC_INVENTORY_SIZE + i); + } + + return items; + } + public static void removeItemExact(final Player player, final ItemStack toRemove, final boolean includeArmor) { removeItems(player, itemStack -> itemStack.equals(toRemove), includeArmor); }