/** * 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.utils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.util.Vector; import pl.betoncraft.betonquest.BetonQuest; import pl.betoncraft.betonquest.InstructionParseException; import pl.betoncraft.betonquest.QuestRuntimeException; import pl.betoncraft.betonquest.api.Variable; import pl.betoncraft.betonquest.config.Config; /** * This class parses various location strings. */ public class LocationData { private Location loc; private Variable variable; private Vector vector = null; private Type type; private enum Type { LOCATION, VARIABLE } /** * Parses the location string. * * @param packName * name of the package, required for variable resolution * @param string * string containing raw location, written like * '100;200;300;world;0;0', where the first three numbers * are x,y,z coordinates, world is name of the world, * followed by optional yaw and pitch. * @throws InstructionParseException * when there is an error while parsing the location */ public LocationData(String packName, String string) throws InstructionParseException { // parse the vector String base = null; if (string.contains("->")) { String[] main = string.split("->"); if (main.length != 2) { throw new InstructionParseException("Incorrect vector format (" + base + ")"); } String vec = main[1]; if (!vec.matches("^\\(-?\\d+.?\\d*;-?\\d+.?\\d*;-?\\d+.?\\d*\\)(;.+)?$")) { throw new InstructionParseException("Incorrect vector format"); } String[] numbers = vec.substring(1, vec.indexOf(')')).split(";"); double x, y, z; try { x = Double.parseDouble(numbers[0]); y = Double.parseDouble(numbers[1]); z = Double.parseDouble(numbers[2]); } catch (NumberFormatException e) { throw new InstructionParseException("Could not parse vector numbers"); } vector = new Vector(x, y, z); base = main[0]; } else { vector = new Vector(0, 0, 0); base = string; } // special keyword "player" is the same as %location% variable // it's used for backwards compatibility if (base.toLowerCase().equals("player")) { base = "%location%"; } // parse the base if (base.startsWith("%") && base.endsWith("%")) { type = Type.VARIABLE; variable = BetonQuest.createVariable(Config.getPackages().get(packName), base); } else { type = Type.LOCATION; loc = parseAbsoluteFormat(base); } } private Location parseAbsoluteFormat(String abs) throws InstructionParseException { String[] parts = abs.split(";"); if (parts.length < 4) { throw new InstructionParseException("Wrong location format (" + abs + ")"); } World world = Bukkit.getWorld(parts[3]); if (world == null) { throw new InstructionParseException("World " + parts[3] + " does not exists."); } double x, y, z; float yaw = 0, pitch = 0; try { x = Double.parseDouble(parts[0]); y = Double.parseDouble(parts[1]); z = Double.parseDouble(parts[2]); if (parts.length == 6) { yaw = Float.parseFloat(parts[4]); pitch = Float.parseFloat(parts[5]); } } catch (NumberFormatException e) { throw new InstructionParseException("Could not parse location coordinates"); } loc = new Location(world, x, y, z, yaw, pitch); return loc; } private Location getBaseLoc(String playerID) throws QuestRuntimeException { switch (type) { case LOCATION: return loc; case VARIABLE: if (playerID == null) { throw new QuestRuntimeException("Variable location cannot accessed without the player;" + " consider changing it to absolute coordinates"); } String value = variable.getValue(playerID); try { return loc = parseAbsoluteFormat(value); } catch (InstructionParseException e) { throw new QuestRuntimeException("Could not resolve a variable to location format: " + e.getMessage()); } default: return null; } } /** * @param playerID * ID of the player, needed for location resolution * @return the location represented by this object * @throws QuestRuntimeException * when location is defined for the player but the player cannot * be accessed */ public Location getLocation(String playerID) throws QuestRuntimeException { return getBaseLoc(playerID).clone().add(vector); } }