/** * BetonQuest - advanced quests for Bukkit * Copyright (C) 2016 Jakub "Co0sh" Sapalski * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package pl.betoncraft.betonquest; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionType; import pl.betoncraft.betonquest.config.ConfigPackage; import pl.betoncraft.betonquest.item.QuestItem; import pl.betoncraft.betonquest.utils.LocationData; public class Instruction { private ConfigPackage pack; private ID id; protected String instruction; protected String[] parts; private int next = 1; private int current = 1; private String lastOptional = null; public Instruction(ConfigPackage pack, ID id, String instruction) { this.pack = pack; try { this.id = id == null ? new NoID(pack) : id; } catch (ObjectNotFoundException e) {} this.instruction = instruction; this.parts = instruction.split(" "); } @Override public String toString() { return instruction; } public String getInstruction() { return instruction; } public int size() { return parts.length; } public ConfigPackage getPackage() { return pack; } public ID getID() { return id; } ///////////////////// /// GENERAL /// ///////////////////// public String next() throws InstructionParseException { lastOptional = null; current = next; return getPart(next++); } public String current() throws InstructionParseException { lastOptional = null; current = next-1; return getPart(current); } public String getPart(int index) throws InstructionParseException { if (parts.length <= index) { throw new InstructionParseException("Not enough arguments"); } lastOptional = null; current = index; return parts[index]; } public String getOptional(String prefix) { for (String part : parts) { if (part.toLowerCase().startsWith(prefix.toLowerCase() + ":")) { lastOptional = prefix; current = -1; return part.substring(prefix.length() + 1); } } return null; } public boolean hasArgument(String argument) { for (String part : parts) { if (part.equalsIgnoreCase(argument)) { return true; } } return false; } ///////////////////// /// OBJECTS /// ///////////////////// public LocationData getLocation() throws InstructionParseException { return getLocation(next()); } public LocationData getLocation(String string) throws InstructionParseException { if (string == null) { return null; } try { return new LocationData(pack.getName(), string); } catch (InstructionParseException e) { throw new PartParseException("Error while parsing location: " + e.getMessage()); } } public VariableNumber getVarNum() throws InstructionParseException { return getVarNum(next()); } public VariableNumber getVarNum(String string) throws InstructionParseException { if (string == null) { return null; } try { return new VariableNumber(pack.getName(), string); } catch (NumberFormatException e) { throw new PartParseException("Could not parse a number: " + e.getMessage()); } } public QuestItem getQuestItem() throws InstructionParseException { return getQuestItem(next()); } private QuestItem getQuestItem(String string) throws InstructionParseException { if (string == null) { return null; } try { return new QuestItem(new ItemID(pack, string)); } catch (ObjectNotFoundException | InstructionParseException e) { throw new PartParseException("Could not load '" + string + "' item: " + e.getMessage()); } } public Item[] getItemList() throws InstructionParseException { return getItemList(next()); } public Item[] getItemList(String string) throws InstructionParseException { String[] array = getArray(string); Item[] items = new Item[array.length]; for (int i = 0; i < items.length; i++) { try { ItemID item; VariableNumber number; if (array[i].contains(":")) { String[] parts = array[i].split(":"); item = getItem(parts[0]); number = getVarNum(parts[1]); } else { item = getItem(array[i]); number = new VariableNumber(1); } items[i] = new Item(item, number); } catch (InstructionParseException | NumberFormatException e) { throw new PartParseException("Error while parsing '" + array[i] + "' item: " + e.getMessage()); } } return items; } public HashMap<Enchantment, Integer> getEnchantments() throws InstructionParseException { return getEnchantments(next()); } public HashMap<Enchantment, Integer> getEnchantments(String string) throws InstructionParseException { if (string == null) { return null; } HashMap<Enchantment, Integer> enchants = new HashMap<>(); String[] array = getArray(string); for (String enchant : array) { String[] enchParts = enchant.split(":"); if (enchParts.length != 2) { throw new PartParseException("Wrong enchantment format: " + enchant); } Enchantment ID = Enchantment.getByName(enchParts[0]); if (ID == null) { throw new PartParseException("Unknown enchantment type: " + enchParts[0]); } Integer level; try { level = new Integer(enchParts[1]); } catch (NumberFormatException e) { throw new PartParseException("Could not parse level in enchant: " + enchant); } enchants.put(ID, level); } return enchants; } public List<PotionEffect> getEffects() throws InstructionParseException { return getEffects(next()); } public List<PotionEffect> getEffects(String string) throws InstructionParseException { if (string == null) { return null; } List<PotionEffect> effects = new ArrayList<>(); String[] array = getArray(string); for (String effect : array) { String[] effParts = effect.split(":"); PotionEffectType ID = PotionEffectType.getByName(effParts[0]); if (ID == null) { throw new PartParseException("Unknown potion effect" + effParts[0]); } int power, duration; try { power = Integer.parseInt(effect.split(":")[1]) - 1; duration = Integer.parseInt(effect.split(":")[2]) * 20; } catch (NumberFormatException e) { throw new PartParseException("Could not parse potion power/duration: " + effect); } effects.add(new PotionEffect(ID, duration, power)); } return effects; } /////////////////// /// Enums /// /////////////////// public <T extends Enum<T>> T getEnum(Class<T> clazz) throws InstructionParseException { return getEnum(next(), clazz); } public <T extends Enum<T>> T getEnum(String string, Class<T> clazz) throws InstructionParseException { if (string == null) { return null; } try { return Enum.valueOf(clazz, string.toUpperCase()); } catch (IllegalArgumentException e) { throw new PartParseException("There is no such " + clazz.getSimpleName() + ": " + string); } } public Material getMaterial() throws InstructionParseException { return Material.matchMaterial(next()); } public Material getMaterial(String string) throws InstructionParseException { return Material.matchMaterial(string); } public EntityType getEntity() throws InstructionParseException { return getEnum(next(), EntityType.class); } public EntityType getEntity(String string) throws InstructionParseException { return getEnum(string, EntityType.class); } public PotionType getPotion() throws InstructionParseException { return getEnum(next(), PotionType.class); } public PotionType getPotion(String string) throws InstructionParseException { return getEnum(string, PotionType.class); } ///////////////// /// IDs /// ///////////////// public EventID getEvent() throws InstructionParseException { return getEvent(next()); } public EventID getEvent(String string) throws InstructionParseException { if (string == null) { return null; } try { return new EventID(pack, string); } catch (ObjectNotFoundException e) { throw new PartParseException("Error while loading event: " + e.getMessage()); } } public ConditionID getCondition() throws InstructionParseException { return getCondition(next()); } public ConditionID getCondition(String string) throws InstructionParseException { if (string == null) { return null; } try { return new ConditionID(pack, string); } catch (ObjectNotFoundException e) { throw new PartParseException("Error while loading condition: " + e.getMessage()); } } public ObjectiveID getObjective() throws InstructionParseException { return getObjective(next()); } public ObjectiveID getObjective(String string) throws InstructionParseException { if (string == null) { return null; } try { return new ObjectiveID(pack, string); } catch (ObjectNotFoundException e) { throw new PartParseException("Error while loading objective: " + e.getMessage()); } } public ItemID getItem() throws InstructionParseException { return getItem(next()); } public ItemID getItem(String string) throws InstructionParseException { if (string == null) { return null; } try { return new ItemID(pack, string); } catch (ObjectNotFoundException e) { throw new PartParseException("Error while loading item: " + e.getMessage()); } } ///////////////////// /// NUMBERS /// ///////////////////// public byte getByte() throws InstructionParseException { return getByte(next(), (byte) 0); } public byte getByte(String string, byte def) throws InstructionParseException { if (string == null) { return def; } try { return Byte.parseByte(string); } catch (NumberFormatException e) { throw new PartParseException("Could not parse byte value: " + string); } } public int getPositive() throws InstructionParseException { return getPositive(next(), 0); } public int getPositive(String string, int def) throws InstructionParseException { int i = getInt(string, def); if (i < 1) { throw new InstructionParseException("Number cannot be less than 1"); } return i; } public int getInt() throws InstructionParseException { return getInt(next(), 0); } public int getInt(String string, int def) throws InstructionParseException { if (string == null) { return def; } try { return Integer.parseInt(string); } catch (NumberFormatException e) { throw new PartParseException("Could not parse a number: " + string); } } public long getLong() throws InstructionParseException { return getLong(next(), 0); } public long getLong(String string, long def) throws InstructionParseException { if (string == null) { return def; } try { return Long.parseLong(string); } catch (NumberFormatException e) { throw new PartParseException("Could not parse a number: " + string); } } public double getDouble() throws InstructionParseException { return getDouble(next(), 0.0); } public double getDouble(String string, double def) throws InstructionParseException { if (string == null) { return def; } try { return Double.parseDouble(string); } catch (NumberFormatException e) { throw new PartParseException("Could not parse decimal value: " + string); } } //////////////////// /// ARRAYS /// //////////////////// public String[] getArray() throws InstructionParseException { return getArray(next()); } public String[] getArray(String string) { if (string == null) { return new String[0]; } return string.split("[,]"); } public <T> List<T> getList(Converter<T> converter) throws InstructionParseException { return getList(next(), converter); } public <T> List<T> getList(String string, Converter<T> converter) throws InstructionParseException { if (string == null) { return new ArrayList<T>(0); } String[] array = getArray(string); List<T> list = new ArrayList<>(array.length); for (String part : array) { list.add(converter.convert(part)); } return list; } ///////////////////////// /// OTHER STUFF /// ///////////////////////// public interface Converter<T> { public T convert(String string) throws InstructionParseException; } public class Item { private ItemID itemID; private QuestItem questItem; private VariableNumber amount; public Item(ItemID itemID, VariableNumber amount) throws InstructionParseException { this.itemID = itemID; this.questItem = new QuestItem(itemID); this.amount = amount; } public ItemID getID() { return itemID; } public QuestItem getItem() { return questItem; } public boolean isItemEqual(ItemStack item) { return questItem.compare(item); } public VariableNumber getAmount() { return amount; } } public class PartParseException extends InstructionParseException { private static final long serialVersionUID = 2007556828888605511L; public PartParseException(String message) { super("Error while parsing " + (lastOptional == null ? current : lastOptional + " optional") + " argument: " + message); } } }