diff options
Diffstat (limited to 'Essentials/src/net/ess3/utils')
15 files changed, 2316 insertions, 0 deletions
diff --git a/Essentials/src/net/ess3/utils/DateUtil.java b/Essentials/src/net/ess3/utils/DateUtil.java new file mode 100644 index 000000000..02916139c --- /dev/null +++ b/Essentials/src/net/ess3/utils/DateUtil.java @@ -0,0 +1,186 @@ +package net.ess3.utils; + +import static net.ess3.I18n._; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DateUtil { + public static String formatDateDiff(long date) + { + Calendar c = new GregorianCalendar(); + c.setTimeInMillis(date); + Calendar now = new GregorianCalendar(); + return formatDateDiff(now, c); + } + + public static String formatDateDiff(Calendar fromDate, Calendar toDate) + { + boolean future = false; + if (toDate.equals(fromDate)) + { + return _("now"); + } + if (toDate.after(fromDate)) + { + future = true; + } + + StringBuilder sb = new StringBuilder(); + int[] types = new int[] + { + Calendar.YEAR, + Calendar.MONTH, + Calendar.DAY_OF_MONTH, + Calendar.HOUR_OF_DAY, + Calendar.MINUTE, + Calendar.SECOND + }; + String[] names = new String[] + { + _("year"), + _("years"), + _("month"), + _("months"), + _("day"), + _("days"), + _("hour"), + _("hours"), + _("minute"), + _("minutes"), + _("second"), + _("seconds") + }; + for (int i = 0; i < types.length; i++) + { + int diff = dateDiff(types[i], fromDate, toDate, future); + if (diff > 0) + { + sb.append(" ").append(diff).append(" ").append(names[i * 2 + (diff > 1 ? 1 : 0)]); + } + } + if (sb.length() == 0) + { + return "now"; + } + return sb.toString(); + } + + private static int dateDiff(int type, Calendar fromDate, Calendar toDate, boolean future) + { + int diff = 0; + long savedDate = fromDate.getTimeInMillis(); + while ((future && !fromDate.after(toDate)) || (!future && !fromDate.before(toDate))) + { + savedDate = fromDate.getTimeInMillis(); + fromDate.add(type, future ? 1 : -1); + diff++; + } + diff--; + fromDate.setTimeInMillis(savedDate); + return diff; + } + + public static long parseDateDiff(String time, boolean future) throws Exception + { + Pattern timePattern = Pattern.compile( + "(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?" + + "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?" + + "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?" + + "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?" + + "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?" + + "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?" + + "(?:([0-9]+)\\s*(?:s[a-z]*)?)?", Pattern.CASE_INSENSITIVE); + Matcher m = timePattern.matcher(time); + int years = 0; + int months = 0; + int weeks = 0; + int days = 0; + int hours = 0; + int minutes = 0; + int seconds = 0; + boolean found = false; + while (m.find()) + { + if (m.group() == null || m.group().isEmpty()) + { + continue; + } + for (int i = 0; i < m.groupCount(); i++) + { + if (m.group(i) != null && !m.group(i).isEmpty()) + { + found = true; + break; + } + } + if (found) + { + if (m.group(1) != null && !m.group(1).isEmpty()) + { + years = Integer.parseInt(m.group(1)); + } + if (m.group(2) != null && !m.group(2).isEmpty()) + { + months = Integer.parseInt(m.group(2)); + } + if (m.group(3) != null && !m.group(3).isEmpty()) + { + weeks = Integer.parseInt(m.group(3)); + } + if (m.group(4) != null && !m.group(4).isEmpty()) + { + days = Integer.parseInt(m.group(4)); + } + if (m.group(5) != null && !m.group(5).isEmpty()) + { + hours = Integer.parseInt(m.group(5)); + } + if (m.group(6) != null && !m.group(6).isEmpty()) + { + minutes = Integer.parseInt(m.group(6)); + } + if (m.group(7) != null && !m.group(7).isEmpty()) + { + seconds = Integer.parseInt(m.group(7)); + } + break; + } + } + if (!found) + { + throw new Exception(_("illegalDate")); + } + Calendar c = new GregorianCalendar(); + if (years > 0) + { + c.add(Calendar.YEAR, years * (future ? 1 : -1)); + } + if (months > 0) + { + c.add(Calendar.MONTH, months * (future ? 1 : -1)); + } + if (weeks > 0) + { + c.add(Calendar.WEEK_OF_YEAR, weeks * (future ? 1 : -1)); + } + if (days > 0) + { + c.add(Calendar.DAY_OF_MONTH, days * (future ? 1 : -1)); + } + if (hours > 0) + { + c.add(Calendar.HOUR_OF_DAY, hours * (future ? 1 : -1)); + } + if (minutes > 0) + { + c.add(Calendar.MINUTE, minutes * (future ? 1 : -1)); + } + if (seconds > 0) + { + c.add(Calendar.SECOND, seconds * (future ? 1 : -1)); + } + return c.getTimeInMillis(); + } +} diff --git a/Essentials/src/net/ess3/utils/DescParseTickFormat.java b/Essentials/src/net/ess3/utils/DescParseTickFormat.java new file mode 100644 index 000000000..bf7d95c23 --- /dev/null +++ b/Essentials/src/net/ess3/utils/DescParseTickFormat.java @@ -0,0 +1,295 @@ +package net.ess3.utils; + +import static net.ess3.I18n._; +import java.text.SimpleDateFormat; +import java.util.*; + + +/** + * This utility class is used for converting between the ingame time in ticks to ingame time as a friendly string. Note + * that the time is INGAME. + * + * http://www.minecraftwiki.net/wiki/Day/night_cycle + * + * @author Olof Larsson + */ +public final class DescParseTickFormat +{ + public static final Map<String, Integer> nameToTicks = new LinkedHashMap<String, Integer>(); + public static final Set<String> resetAliases = new HashSet<String>(); + public static final int ticksAtMidnight = 18000; + public static final int ticksPerDay = 24000; + public static final int ticksPerHour = 1000; + public static final double ticksPerMinute = 1000d / 60d; + public static final double ticksPerSecond = 1000d / 60d / 60d; + private static final SimpleDateFormat SDFTwentyFour = new SimpleDateFormat("HH:mm", Locale.ENGLISH); + private static final SimpleDateFormat SDFTwelve = new SimpleDateFormat("h:mmaa", Locale.ENGLISH); + + static + { + SDFTwentyFour.setTimeZone(TimeZone.getTimeZone("GMT")); + SDFTwelve.setTimeZone(TimeZone.getTimeZone("GMT")); + + nameToTicks.put("sunrise", 23000); + nameToTicks.put("dawn", 23000); + + nameToTicks.put("daystart", 0); + nameToTicks.put("day", 0); + + nameToTicks.put("morning", 1000); + + nameToTicks.put("midday", 6000); + nameToTicks.put("noon", 6000); + + nameToTicks.put("afternoon", 9000); + + nameToTicks.put("sunset", 12000); + nameToTicks.put("dusk", 12000); + nameToTicks.put("sundown", 12000); + nameToTicks.put("nightfall", 12000); + + nameToTicks.put("nightstart", 14000); + nameToTicks.put("night", 14000); + + nameToTicks.put("midnight", 18000); + + resetAliases.add("reset"); + resetAliases.add("normal"); + resetAliases.add("default"); + } + + private DescParseTickFormat() + { + } + + // ============================================ + // PARSE. From describing String to int + // -------------------------------------------- + public static long parse(String desc) throws NumberFormatException + { + // Only look at alphanumeric and lowercase and : for 24:00 + desc = desc.toLowerCase(Locale.ENGLISH).replaceAll("[^A-Za-z0-9:]", ""); + + // Detect ticks format + try + { + return parseTicks(desc); + } + catch (Exception e) + { + } + + // Detect 24-hour format + try + { + return parse24(desc); + } + catch (Exception e) + { + } + + // Detect 12-hour format + try + { + return parse12(desc); + } + catch (Exception e) + { + } + + // Detect aliases + try + { + return parseAlias(desc); + } + catch (Exception e) + { + } + + // Well we failed to understand... + throw new NumberFormatException(); + } + + public static long parseTicks(String desc) throws NumberFormatException + { + if (!desc.matches("^[0-9]+ti?c?k?s?$")) + { + throw new NumberFormatException(); + } + + desc = desc.replaceAll("[^0-9]", ""); + + return Long.parseLong(desc) % 24000; + } + + public static long parse24(String desc) throws NumberFormatException + { + if (!desc.matches("^[0-9]{2}[^0-9]?[0-9]{2}$")) + { + throw new NumberFormatException(); + } + + desc = desc.toLowerCase(Locale.ENGLISH).replaceAll("[^0-9]", ""); + + if (desc.length() != 4) + { + throw new NumberFormatException(); + } + + final int hours = Integer.parseInt(desc.substring(0, 2)); + final int minutes = Integer.parseInt(desc.substring(2, 4)); + + return hoursMinutesToTicks(hours, minutes); + } + + public static long parse12(String desc) throws NumberFormatException + { + if (!desc.matches("^[0-9]{1,2}([^0-9]?[0-9]{2})?(pm|am)$")) + { + throw new NumberFormatException(); + } + + int hours = 0; + int minutes = 0; + + desc = desc.toLowerCase(Locale.ENGLISH); + String parsetime = desc.replaceAll("[^0-9]", ""); + + if (parsetime.length() > 4) + { + throw new NumberFormatException(); + } + + if (parsetime.length() == 4) + { + hours += Integer.parseInt(parsetime.substring(0, 2)); + minutes += Integer.parseInt(parsetime.substring(2, 4)); + } + else if (parsetime.length() == 3) + { + hours += Integer.parseInt(parsetime.substring(0, 1)); + minutes += Integer.parseInt(parsetime.substring(1, 3)); + } + else if (parsetime.length() == 2) + { + hours += Integer.parseInt(parsetime.substring(0, 2)); + } + else if (parsetime.length() == 1) + { + hours += Integer.parseInt(parsetime.substring(0, 1)); + } + else + { + throw new NumberFormatException(); + } + + if (desc.endsWith("pm") && hours != 12) + { + hours += 12; + } + + if (desc.endsWith("am") && hours == 12) + { + hours -= 12; + } + + return hoursMinutesToTicks(hours, minutes); + } + + public static long hoursMinutesToTicks(final int hours, final int minutes) + { + long ret = ticksAtMidnight; + ret += (hours) * ticksPerHour; + + ret += (minutes / 60.0) * ticksPerHour; + + ret %= ticksPerDay; + return ret; + } + + public static long parseAlias(final String desc) throws NumberFormatException + { + final Integer ret = nameToTicks.get(desc); + if (ret == null) + { + throw new NumberFormatException(); + } + + return ret; + } + + public static boolean meansReset(final String desc) + { + return resetAliases.contains(desc); + } + + // ============================================ + // FORMAT. From int to describing String + // -------------------------------------------- + public static String format(final long ticks) + { + return _("timeFormat", format24(ticks), format12(ticks), formatTicks(ticks)); + } + + public static String formatTicks(final long ticks) + { + return (ticks % ticksPerDay) + "ticks"; + } + + public static String format24(final long ticks) + { + synchronized (SDFTwentyFour) + { + return formatDateFormat(ticks, SDFTwentyFour); + } + } + + public static String format12(final long ticks) + { + synchronized (SDFTwelve) + { + return formatDateFormat(ticks, SDFTwelve); + } + } + + public static String formatDateFormat(final long ticks, final SimpleDateFormat format) + { + final Date date = ticksToDate(ticks); + return format.format(date); + } + + public static Date ticksToDate(long ticks) + { + // Assume the server time starts at 0. It would start on a day. + // But we will simulate that the server started with 0 at midnight. + ticks = ticks - ticksAtMidnight + ticksPerDay; + + // How many ingame days have passed since the server start? + final long days = ticks / ticksPerDay; + ticks = ticks - days * ticksPerDay; + + // How many hours on the last day? + final long hours = ticks / ticksPerHour; + ticks = ticks - hours * ticksPerHour; + + // How many minutes on the last day? + final long minutes = (long)Math.floor(ticks / ticksPerMinute); + final double dticks = ticks - minutes * ticksPerMinute; + + // How many seconds on the last day? + final long seconds = (long)Math.floor(dticks / ticksPerSecond); + + // Now we create an english GMT calendar (We wan't no daylight savings) + final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.ENGLISH); + cal.setLenient(true); + + // And we set the time to 0! And append the time that passed! + cal.set(0, Calendar.JANUARY, 1, 0, 0, 0); + cal.add(Calendar.DAY_OF_YEAR, (int)days); + cal.add(Calendar.HOUR_OF_DAY, (int)hours); + cal.add(Calendar.MINUTE, (int)minutes); + cal.add(Calendar.SECOND, (int)seconds + 1); // To solve rounding errors. + + return cal.getTime(); + } +} diff --git a/Essentials/src/net/ess3/utils/ExecuteTimer.java b/Essentials/src/net/ess3/utils/ExecuteTimer.java new file mode 100644 index 000000000..2f0c7a5f6 --- /dev/null +++ b/Essentials/src/net/ess3/utils/ExecuteTimer.java @@ -0,0 +1,89 @@ +package net.ess3.utils; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + + +public class ExecuteTimer +{ + private final transient List<ExecuteRecord> times; + private final transient DecimalFormat decimalFormat = new DecimalFormat("#0.000", DecimalFormatSymbols.getInstance(Locale.US)); + + + public ExecuteTimer() + { + times = new ArrayList<ExecuteRecord>(); + } + + public void start() + { + times.clear(); + mark("start"); + + } + + public void mark(final String label) + { + if (!times.isEmpty() || "start".equals(label)) + { + times.add(new ExecuteRecord(label, System.nanoTime())); + } + } + + public String end() + { + final StringBuilder output = new StringBuilder(); + output.append("execution time: "); + String mark; + long time0 = 0; + long time1 = 0; + long time2 = 0; + double duration; + + for (ExecuteRecord pair : times) + { + mark = (String)pair.getMark(); + time2 = (Long)pair.getTime(); + if (time1 > 0) + { + duration = (time2 - time1)/1000000.0; + output.append(mark).append(": ").append(decimalFormat.format(duration)).append("ms - "); + } + else + { + time0 = time2; + } + time1 = time2; + } + duration = (time1 - time0)/1000000.0; + output.append("Total: ").append(decimalFormat.format(duration)).append("ms"); + times.clear(); + return output.toString(); + } + + + static private class ExecuteRecord + { + private final String mark; + private final long time; + + public ExecuteRecord(final String mark, final long time) + { + this.mark = mark; + this.time = time; + } + + public String getMark() + { + return mark; + } + + public long getTime() + { + return time; + } + } +}
\ No newline at end of file diff --git a/Essentials/src/net/ess3/utils/LocationUtil.java b/Essentials/src/net/ess3/utils/LocationUtil.java new file mode 100644 index 000000000..61cdcec6e --- /dev/null +++ b/Essentials/src/net/ess3/utils/LocationUtil.java @@ -0,0 +1,142 @@ +package net.ess3.utils; + +import static net.ess3.I18n._; +import java.util.HashSet; +import java.util.Set; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.LivingEntity; + +public class LocationUtil { + // The player can stand inside these materials + private static final Set<Integer> AIR_MATERIALS = new HashSet<Integer>(); + private static final HashSet<Byte> AIR_MATERIALS_TARGET = new HashSet<Byte>(); + + static + { + AIR_MATERIALS.add(Material.AIR.getId()); + AIR_MATERIALS.add(Material.SAPLING.getId()); + AIR_MATERIALS.add(Material.POWERED_RAIL.getId()); + AIR_MATERIALS.add(Material.DETECTOR_RAIL.getId()); + AIR_MATERIALS.add(Material.LONG_GRASS.getId()); + AIR_MATERIALS.add(Material.DEAD_BUSH.getId()); + AIR_MATERIALS.add(Material.YELLOW_FLOWER.getId()); + AIR_MATERIALS.add(Material.RED_ROSE.getId()); + AIR_MATERIALS.add(Material.BROWN_MUSHROOM.getId()); + AIR_MATERIALS.add(Material.RED_MUSHROOM.getId()); + AIR_MATERIALS.add(Material.TORCH.getId()); + AIR_MATERIALS.add(Material.REDSTONE_WIRE.getId()); + AIR_MATERIALS.add(Material.SEEDS.getId()); + AIR_MATERIALS.add(Material.SIGN_POST.getId()); + AIR_MATERIALS.add(Material.WOODEN_DOOR.getId()); + AIR_MATERIALS.add(Material.LADDER.getId()); + AIR_MATERIALS.add(Material.RAILS.getId()); + AIR_MATERIALS.add(Material.WALL_SIGN.getId()); + AIR_MATERIALS.add(Material.LEVER.getId()); + AIR_MATERIALS.add(Material.STONE_PLATE.getId()); + AIR_MATERIALS.add(Material.IRON_DOOR_BLOCK.getId()); + AIR_MATERIALS.add(Material.WOOD_PLATE.getId()); + AIR_MATERIALS.add(Material.REDSTONE_TORCH_OFF.getId()); + AIR_MATERIALS.add(Material.REDSTONE_TORCH_ON.getId()); + AIR_MATERIALS.add(Material.STONE_BUTTON.getId()); + AIR_MATERIALS.add(Material.SUGAR_CANE_BLOCK.getId()); + AIR_MATERIALS.add(Material.DIODE_BLOCK_OFF.getId()); + AIR_MATERIALS.add(Material.DIODE_BLOCK_ON.getId()); + AIR_MATERIALS.add(Material.TRAP_DOOR.getId()); + AIR_MATERIALS.add(Material.PUMPKIN_STEM.getId()); + AIR_MATERIALS.add(Material.MELON_STEM.getId()); + AIR_MATERIALS.add(Material.VINE.getId()); + AIR_MATERIALS.add(Material.NETHER_WARTS.getId()); + AIR_MATERIALS.add(Material.WATER_LILY.getId()); + + for (Integer integer : AIR_MATERIALS) + { + AIR_MATERIALS_TARGET.add(integer.byteValue()); + } + AIR_MATERIALS_TARGET.add((byte)Material.WATER.getId()); + AIR_MATERIALS_TARGET.add((byte)Material.STATIONARY_WATER.getId()); + } + + public static Location getTarget(final LivingEntity entity) throws Exception + { + final Block block = entity.getTargetBlock(AIR_MATERIALS_TARGET, 300); + if (block == null) + { + throw new Exception("Not targeting a block"); + } + return block.getLocation(); + } + + public static Location getSafeDestination(final Location loc) throws Exception + { + if (loc == null || loc.getWorld() == null) + { + throw new Exception(_("destinationNotSet")); + } + final World world = loc.getWorld(); + int x = loc.getBlockX(); + int y = (int)Math.round(loc.getY()); + int z = loc.getBlockZ(); + + while (isBlockAboveAir(world, x, y, z)) + { + y -= 1; + if (y < 0) + { + break; + } + } + + while (isBlockUnsafe(world, x, y, z)) + { + y += 1; + if (y >= world.getHighestBlockYAt(x, z)) + { + x += 1; + break; + } + } + while (isBlockUnsafe(world, x, y, z)) + { + y -= 1; + if (y <= 1) + { + x += 1; + y = world.getHighestBlockYAt(x, z); + if (x - 32 > loc.getBlockX()) + { + throw new Exception(_("holeInFloor")); + } + } + } + return new Location(world, x + 0.5D, y, z + 0.5D, loc.getYaw(), loc.getPitch()); + } + + private static boolean isBlockAboveAir(final World world, final int x, final int y, final int z) + { + return AIR_MATERIALS.contains(world.getBlockAt(x, y - 1, z).getType().getId()); + } + + public static boolean isBlockUnsafe(final World world, final int x, final int y, final int z) + { + final Block below = world.getBlockAt(x, y - 1, z); + if (below.getType() == Material.LAVA || below.getType() == Material.STATIONARY_LAVA) + { + return true; + } + + if (below.getType() == Material.FIRE) + { + return true; + } + + if ((!AIR_MATERIALS.contains(world.getBlockAt(x, y, z).getType().getId())) + || (!AIR_MATERIALS.contains(world.getBlockAt(x, y + 1, z).getType().getId()))) + { + return true; + } + return isBlockAboveAir(world, x, y, z); + } +} diff --git a/Essentials/src/net/ess3/utils/Util.java b/Essentials/src/net/ess3/utils/Util.java new file mode 100644 index 000000000..8121f8ff8 --- /dev/null +++ b/Essentials/src/net/ess3/utils/Util.java @@ -0,0 +1,442 @@ +package net.ess3.utils; + +import static net.ess3.I18n._; +import net.ess3.api.IEssentials; +import net.ess3.api.ISettings; +import net.ess3.api.IUser; +import net.ess3.api.InvalidNameException; +import net.ess3.utils.gnu.inet.encoding.Punycode; +import net.ess3.utils.gnu.inet.encoding.PunycodeException; +import de.bananaco.bpermissions.imp.Permissions; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Collection; +import java.util.Locale; +import java.util.regex.Pattern; +import lombok.Cleanup; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; +import org.bukkit.plugin.PluginManager; + + +public final class Util +{ + private Util() + { + } + private final static Pattern INVALIDFILECHARS = Pattern.compile("[^\u0020-\u007E\u0085\u00A0-\uD7FF\uE000-\uFFFC]"); + private final static Pattern INVALIDCHARS = Pattern.compile("[^\t\n\r\u0020-\u007E\u0085\u00A0-\uD7FF\uE000-\uFFFC]"); + + public static String sanitizeFileName(String name) throws InvalidNameException + { + try + { + String r = name.toLowerCase(Locale.ENGLISH); + r = r.replace('.', (char)('\ue200' + '.')); + r = r.replace('\\', (char)('\ue200' + '\\')); + r = r.replace('/', (char)('\ue200' + '/')); + r = r.replace('"', (char)('\ue200' + '"')); + r = r.replace('<', (char)('\ue200' + '<')); + r = r.replace('>', (char)('\ue200' + '>')); + r = r.replace('|', (char)('\ue200' + '|')); + r = r.replace('?', (char)('\ue200' + '?')); + r = r.replace('*', (char)('\ue200' + '*')); + r = r.replace(':', (char)('\ue200' + ':')); + r = r.replace('-', (char)('\ue200' + '-')); + r = INVALIDFILECHARS.matcher(r).replaceAll(""); + return Punycode.encode(r); + } + catch (PunycodeException ex) + { + throw new InvalidNameException(ex); + } + } + + public static String decodeFileName(String name) throws InvalidNameException + { + try + { + String r = Punycode.decode(name); + r = r.replace((char)('\ue200' + '.'), '.'); + r = r.replace((char)('\ue200' + '\\'), '\\'); + r = r.replace((char)('\ue200' + '/'), '/'); + r = r.replace((char)('\ue200' + '"'), '"'); + r = r.replace((char)('\ue200' + '<'), '<'); + r = r.replace((char)('\ue200' + '>'), '>'); + r = r.replace((char)('\ue200' + '|'), '|'); + r = r.replace((char)('\ue200' + '?'), '?'); + r = r.replace((char)('\ue200' + '*'), '*'); + r = r.replace((char)('\ue200' + ':'), ':'); + r = r.replace((char)('\ue200' + '-'), '-'); + return r; + } + catch (PunycodeException ex) + { + throw new InvalidNameException(ex); + } + } + + public static String sanitizeKey(String name) + { + return INVALIDCHARS.matcher(name.toLowerCase(Locale.ENGLISH)).replaceAll("_"); + } + + public static String sanitizeString(final String string) + { + return INVALIDCHARS.matcher(string).replaceAll(""); + } + + public static ItemStack convertBlockToItem(final Block block) + { + final ItemStack is = new ItemStack(block.getType(), 1, (short)0, block.getData()); + switch (is.getType()) + { + case WOODEN_DOOR: + is.setType(Material.WOOD_DOOR); + is.setDurability((short)0); + break; + case IRON_DOOR_BLOCK: + is.setType(Material.IRON_DOOR); + is.setDurability((short)0); + break; + case SIGN_POST: + case WALL_SIGN: + is.setType(Material.SIGN); + is.setDurability((short)0); + break; + case CROPS: + is.setType(Material.SEEDS); + is.setDurability((short)0); + break; + case CAKE_BLOCK: + is.setType(Material.CAKE); + is.setDurability((short)0); + break; + case BED_BLOCK: + is.setType(Material.BED); + is.setDurability((short)0); + break; + case REDSTONE_WIRE: + is.setType(Material.REDSTONE); + is.setDurability((short)0); + break; + case REDSTONE_TORCH_OFF: + case REDSTONE_TORCH_ON: + is.setType(Material.REDSTONE_TORCH_ON); + is.setDurability((short)0); + break; + case DIODE_BLOCK_OFF: + case DIODE_BLOCK_ON: + is.setType(Material.DIODE); + is.setDurability((short)0); + break; + case DOUBLE_STEP: + is.setType(Material.STEP); + break; + case TORCH: + case RAILS: + case LADDER: + case WOOD_STAIRS: + case COBBLESTONE_STAIRS: + case LEVER: + case STONE_BUTTON: + case FURNACE: + case DISPENSER: + case PUMPKIN: + case JACK_O_LANTERN: + case WOOD_PLATE: + case STONE_PLATE: + case PISTON_STICKY_BASE: + case PISTON_BASE: + case IRON_FENCE: + case THIN_GLASS: + case TRAP_DOOR: + case FENCE: + case FENCE_GATE: + case NETHER_FENCE: + is.setDurability((short)0); + break; + case FIRE: + return null; + case PUMPKIN_STEM: + is.setType(Material.PUMPKIN_SEEDS); + break; + case MELON_STEM: + is.setType(Material.MELON_SEEDS); + break; + } + return is; + } + private static DecimalFormat dFormat = new DecimalFormat("#0.00", DecimalFormatSymbols.getInstance(Locale.US)); + + public static String formatAsCurrency(final double value) + { + + String str = dFormat.format(value); + if (str.endsWith(".00")) + { + str = str.substring(0, str.length() - 3); + } + return str; + } + + public static String displayCurrency(final double value, final IEssentials ess) + { + @Cleanup + final ISettings settings = ess.getSettings(); + settings.acquireReadLock(); + return _("currency", settings.getData().getEconomy().getCurrencySymbol(), formatAsCurrency(value)); + } + + public static String shortCurrency(final double value, final IEssentials ess) + { + @Cleanup + final ISettings settings = ess.getSettings(); + settings.acquireReadLock(); + return settings.getData().getEconomy().getCurrencySymbol() + formatAsCurrency(value); + } + + public static double roundDouble(final double d) + { + return Math.round(d * 100.0) / 100.0; + } + + public static boolean isInt(final String sInt) + { + try + { + Integer.parseInt(sInt); + } + catch (NumberFormatException e) + { + return false; + } + return true; + } + + public static String joinList(Object... list) + { + return joinList(", ", list); + } + + public static String joinList(String seperator, Object... list) + { + StringBuilder buf = new StringBuilder(); + for (Object each : list) + { + if (buf.length() > 0) + { + buf.append(seperator); + } + + if (each instanceof Collection) + { + buf.append(joinList(seperator, ((Collection)each).toArray())); + } + else + { + try + { + buf.append(each.toString()); + } + catch (Exception e) + { + buf.append(each.toString()); + } + } + } + return buf.toString(); + } + + public static void registerPermissions(String path, Collection<String> nodes, boolean hasDefault, IEssentials ess) + { + if (nodes == null || nodes.isEmpty()) + { + return; + } + final PluginManager pluginManager = ess.getServer().getPluginManager(); + Permission basePerm = pluginManager.getPermission(path + ".*"); + if (basePerm != null && !basePerm.getChildren().isEmpty()) + { + basePerm.getChildren().clear(); + } + if (basePerm == null) + { + basePerm = new Permission(path + ".*", PermissionDefault.OP); + pluginManager.addPermission(basePerm); + Permission mainPerm = pluginManager.getPermission("essentials.*"); + if (mainPerm == null) + { + mainPerm = new Permission("essentials.*", PermissionDefault.OP); + pluginManager.addPermission(mainPerm); + } + mainPerm.getChildren().put(basePerm.getName(), Boolean.TRUE); + } + + for (String nodeName : nodes) + { + final String permissionName = path + "." + nodeName; + Permission perm = pluginManager.getPermission(permissionName); + if (perm == null) + { + final PermissionDefault defaultPerm = hasDefault && nodeName.equalsIgnoreCase("default") ? PermissionDefault.TRUE : PermissionDefault.OP; + perm = new Permission(permissionName, defaultPerm); + pluginManager.addPermission(perm); + } + basePerm.getChildren().put(permissionName, Boolean.TRUE); + } + basePerm.recalculatePermissibles(); + } + private static transient final Pattern DOT_PATTERN = Pattern.compile("\\."); + + public static Permission registerPermission(String permission, PermissionDefault defaultPerm) + { + final PluginManager pluginManager = Bukkit.getServer().getPluginManager(); + final String[] parts = DOT_PATTERN.split(permission); + final StringBuilder builder = new StringBuilder(permission.length()); + Permission parent = null; + for (int i = 0; i < parts.length - 1; i++) + { + builder.append(parts[i]).append(".*"); + String permString = builder.toString(); + Permission perm = pluginManager.getPermission(permString); + if (perm == null) + { + perm = new Permission(permString, PermissionDefault.FALSE); + pluginManager.addPermission(perm); + if (parent != null) + { + parent.getChildren().put(perm.getName(), Boolean.TRUE); + } + parent = perm; + } + builder.deleteCharAt(builder.length() - 1); + } + Permission perm = pluginManager.getPermission(permission); + if (perm == null) + { + perm = new Permission(permission, defaultPerm); + pluginManager.addPermission(perm); + if (parent != null) + { + parent.getChildren().put(perm.getName(), Boolean.TRUE); + } + parent = perm; + } + perm.recalculatePermissibles(); + return perm; + } + private static transient final Pattern URL_PATTERN = Pattern.compile("((?:(?:https?)://)?[\\w-_\\.]{2,})\\.([a-z]{2,3}(?:/\\S+)?)"); + private static transient final Pattern VANILLA_PATTERN = Pattern.compile("\u00A7+[0-9A-FK-ORa-fk-or]"); + private static transient final Pattern REPLACE_PATTERN = Pattern.compile("&([0-9a-fk-or])"); + private static transient final Pattern VANILLA_COLOR_PATTERN = Pattern.compile("\u00A7+[0-9A-Fa-f]"); + private static transient final Pattern VANILLA_MAGIC_PATTERN = Pattern.compile("\u00A7+[Kk]"); + private static transient final Pattern VANILLA_FORMAT_PATTERN = Pattern.compile("\u00A7+[L-ORl-or]"); + private static transient final Pattern REPLACE_COLOR_PATTERN = Pattern.compile("&([0-9a-f])"); + private static transient final Pattern REPLACE_MAGIC_PATTERN = Pattern.compile("&(k)"); + private static transient final Pattern REPLACE_FORMAT_PATTERN = Pattern.compile("&([l-or])"); + + public static String stripFormat(final String input) + { + if (input == null) + { + return null; + } + return VANILLA_PATTERN.matcher(input).replaceAll(""); + } + + public static String replaceFormat(final String input) + { + if (input == null) + { + return null; + } + return REPLACE_PATTERN.matcher(input).replaceAll("\u00a7$1"); + } + + public static String blockURL(final String input) + { + if (input == null) + { + return null; + } + String text = URL_PATTERN.matcher(input).replaceAll("$1 $2"); + while (URL_PATTERN.matcher(text).find()) + { + text = URL_PATTERN.matcher(text).replaceAll("$1 $2"); + } + return text; + } + + public static String formatString(final IUser user, final String permBase, final String input) + { + if (input == null) + { + return null; + } + String message; + if (Permissions.hasPermission(user.getBase(), permBase + ".color")) + { + message = Util.replaceColor(input, REPLACE_COLOR_PATTERN); + } + else + { + message = Util.stripColor(input, VANILLA_COLOR_PATTERN); + } + if (Permissions.hasPermission(user.getBase(), permBase + ".magic")) + { + message = Util.replaceColor(message, REPLACE_MAGIC_PATTERN); + } + else + { + message = Util.stripColor(message, VANILLA_MAGIC_PATTERN); + } + if (Permissions.hasPermission(user.getBase(), permBase + ".format")) + { + message = Util.replaceColor(message, REPLACE_FORMAT_PATTERN); + } + else + { + message = Util.stripColor(message, VANILLA_FORMAT_PATTERN); + } + return message; + } + + public static String formatMessage(final IUser user, final String permBase, final String input) + { + if (input == null) + { + return null; + } + String message = formatString(user, permBase, input); + if (!Permissions.hasPermission(user.getBase(), permBase + ".url")) + { + message = Util.blockURL(message); + } + return message; + } + + public static String stripColor(final String input) + { + if (input == null) + { + return null; + } + + return VANILLA_COLOR_PATTERN.matcher(input).replaceAll(""); + } + + private static String stripColor(final String input, final Pattern pattern) + { + return pattern.matcher(input).replaceAll(""); + } + + private static String replaceColor(final String input, final Pattern pattern) + { + return pattern.matcher(input).replaceAll("\u00a7$1"); + } +} diff --git a/Essentials/src/net/ess3/utils/gnu/inet/encoding/Punycode.java b/Essentials/src/net/ess3/utils/gnu/inet/encoding/Punycode.java new file mode 100644 index 000000000..8d8aa3750 --- /dev/null +++ b/Essentials/src/net/ess3/utils/gnu/inet/encoding/Punycode.java @@ -0,0 +1,321 @@ +package net.ess3.utils.gnu.inet.encoding; + + +/** + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software + * Foundation, Inc. + * + * Author: Oliver Hitz + * + * This file is part of GNU Libidn. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +/** + * This class offers static methods for encoding/decoding strings + * using the Punycode algorithm. + * <ul> + * <li>RFC3492 Punycode + * </ul> + * Note that this implementation only supports 16-bit Unicode code + * points. + */ +/* + * Changes by snowleo: + * - Correctly catch wrong characters after the delimiter + * - If the string starts with the delimiter, it's an encoded string + * - If there is no delimiter, it's an ascii string. + * - Note: the string should never contain the delimiter. + */ +public class Punycode +{ + /* + * Punycode parameters + */ + final static int TMIN = 1; + final static int TMAX = 26; + final static int BASE = 36; + final static int INITIAL_N = 128; + final static int INITIAL_BIAS = 72; + final static int DAMP = 700; + final static int SKEW = 38; + final static char DELIMITER = '-'; + + /** + * Punycodes a unicode string. + * + * @param input Unicode string. + * @return Punycoded string. + */ + public static String encode(String input) + throws PunycodeException + { + int n = INITIAL_N; + int delta = 0; + int bias = INITIAL_BIAS; + StringBuffer output = new StringBuffer(); + + // Copy all basic code points to the output + int b = 0; + for (int i = 0; i < input.length(); i++) + { + char c = input.charAt(i); + if (isBasic(c)) + { + output.append(c); + b++; + } + } + + // Append delimiter + if (b < input.length()) // Changed by snowleo + { + output.append(DELIMITER); + } + + int h = b; + while (h < input.length()) + { + int m = Integer.MAX_VALUE; + + // Find the minimum code point >= n + for (int i = 0; i < input.length(); i++) + { + int c = input.charAt(i); + if (c >= n && c < m) + { + m = c; + } + } + + if (m - n > (Integer.MAX_VALUE - delta) / (h + 1)) + { + throw new PunycodeException(PunycodeException.OVERFLOW); + } + delta = delta + (m - n) * (h + 1); + n = m; + + for (int j = 0; j < input.length(); j++) + { + int c = input.charAt(j); + if (c < n) + { + delta++; + if (0 == delta) + { + throw new PunycodeException(PunycodeException.OVERFLOW); + } + } + if (c == n) + { + int q = delta; + + for (int k = BASE;; k += BASE) + { + int t; + if (k <= bias) + { + t = TMIN; + } + else if (k >= bias + TMAX) + { + t = TMAX; + } + else + { + t = k - bias; + } + if (q < t) + { + break; + } + output.append((char)digit2codepoint(t + (q - t) % (BASE - t))); + q = (q - t) / (BASE - t); + } + + output.append((char)digit2codepoint(q)); + bias = adapt(delta, h + 1, h == b); + delta = 0; + h++; + } + } + + delta++; + n++; + } + + return output.toString(); + } + + /** + * Decode a punycoded string. + * + * @param input Punycode string + * @return Unicode string. + */ + public static String decode(String input) + throws PunycodeException + { + int n = INITIAL_N; + int i = 0; + int bias = INITIAL_BIAS; + StringBuffer output = new StringBuffer(); + + int d = input.lastIndexOf(DELIMITER); + // Change start by snowleo + if (d < 0) { + return input; + } + else if (d > 0) // Change end by snowleo + { + for (int j = 0; j < d; j++) + { + char c = input.charAt(j); + if (!isBasic(c)) + { + throw new PunycodeException(PunycodeException.BAD_INPUT); + } + output.append(c); + } + d++; + } + else + { + d = 1; // Changed by snowleo + } + + while (d < input.length()) + { + int oldi = i; + int w = 1; + + for (int k = BASE;; k += BASE) + { + if (d == input.length()) + { + throw new PunycodeException(PunycodeException.BAD_INPUT); + } + int c = input.charAt(d++); + int digit = codepoint2digit(c); + if (digit > (Integer.MAX_VALUE - i) / w) + { + throw new PunycodeException(PunycodeException.OVERFLOW); + } + + i = i + digit * w; + + int t; + if (k <= bias) + { + t = TMIN; + } + else if (k >= bias + TMAX) + { + t = TMAX; + } + else + { + t = k - bias; + } + if (digit < t) + { + break; + } + w = w * (BASE - t); + } + + bias = adapt(i - oldi, output.length() + 1, oldi == 0); + + if (i / (output.length() + 1) > Integer.MAX_VALUE - n) + { + throw new PunycodeException(PunycodeException.OVERFLOW); + } + + n = n + i / (output.length() + 1); + i = i % (output.length() + 1); + output.insert(i, (char)n); + i++; + } + + return output.toString(); + } + + public final static int adapt(int delta, int numpoints, boolean first) + { + if (first) + { + delta = delta / DAMP; + } + else + { + delta = delta / 2; + } + + delta = delta + (delta / numpoints); + + int k = 0; + while (delta > ((BASE - TMIN) * TMAX) / 2) + { + delta = delta / (BASE - TMIN); + k = k + BASE; + } + + return k + ((BASE - TMIN + 1) * delta) / (delta + SKEW); + } + + public final static boolean isBasic(char c) + { + return c < 0x80; + } + + public final static int digit2codepoint(int d) + throws PunycodeException + { + if (d < 26) + { + // 0..25 : 'a'..'z' + return d + 'a'; + } + else if (d < 36) + { + // 26..35 : '0'..'9'; + return d - 26 + '0'; + } + else + { + throw new PunycodeException(PunycodeException.BAD_INPUT); + } + } + + public final static int codepoint2digit(int c) + throws PunycodeException + { + if (c - '0' < 10 && c >= '0') // Changed by snowleo + { + // '0'..'9' : 26..35 + return c - '0' + 26; + } + else if (c - 'a' < 26 && c >= 'a') // Changed by snowleo + { + // 'a'..'z' : 0..25 + return c - 'a'; + } + else + { + throw new PunycodeException(PunycodeException.BAD_INPUT); + } + } +} diff --git a/Essentials/src/net/ess3/utils/gnu/inet/encoding/PunycodeException.java b/Essentials/src/net/ess3/utils/gnu/inet/encoding/PunycodeException.java new file mode 100644 index 000000000..1f9649813 --- /dev/null +++ b/Essentials/src/net/ess3/utils/gnu/inet/encoding/PunycodeException.java @@ -0,0 +1,45 @@ +package net.ess3.utils.gnu.inet.encoding; + + +/** + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software + * Foundation, Inc. + * + * Author: Oliver Hitz + * + * This file is part of GNU Libidn. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ +/** + * Exception handling for Punycode class. + */ +public class PunycodeException + extends Exception +{ + public static String OVERFLOW = "Overflow."; + public static String BAD_INPUT = "Bad input."; + + /** + * Creates a new PunycodeException. + * + * @param m message. + */ + public PunycodeException(String m) + { + super(m); + } +} diff --git a/Essentials/src/net/ess3/utils/textreader/ArrayListInput.java b/Essentials/src/net/ess3/utils/textreader/ArrayListInput.java new file mode 100644 index 000000000..4f3a915f2 --- /dev/null +++ b/Essentials/src/net/ess3/utils/textreader/ArrayListInput.java @@ -0,0 +1,31 @@ +package net.ess3.utils.textreader; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + + +public class ArrayListInput implements IText +{ + private final transient List<String> lines = new ArrayList<String>(); + + @Override + public List<String> getLines() + { + return lines; + } + + @Override + public List<String> getChapters() + { + return Collections.emptyList(); + } + + @Override + public Map<String, Integer> getBookmarks() + { + return Collections.emptyMap(); + } + +} diff --git a/Essentials/src/net/ess3/utils/textreader/HelpInput.java b/Essentials/src/net/ess3/utils/textreader/HelpInput.java new file mode 100644 index 000000000..109cc3702 --- /dev/null +++ b/Essentials/src/net/ess3/utils/textreader/HelpInput.java @@ -0,0 +1,179 @@ +package net.ess3.utils.textreader; + +import static net.ess3.I18n._; +import net.ess3.api.IEssentials; +import net.ess3.api.ISettings; +import net.ess3.api.IUser; +import net.ess3.permissions.HelpPermissions; +import java.io.IOException; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; +import lombok.Cleanup; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginDescriptionFile; + + +public class HelpInput implements IText +{ + private static final String DESCRIPTION = "description"; + private static final String PERMISSION = "permission"; + private static final String PERMISSIONS = "permissions"; + private final transient List<String> lines = new ArrayList<String>(); + private final transient List<String> chapters = new ArrayList<String>(); + private final transient Map<String, Integer> bookmarks = new HashMap<String, Integer>(); + private final static Logger logger = Logger.getLogger("Minecraft"); + + public HelpInput(final IUser user, final String match, final IEssentials ess) throws IOException + { + @Cleanup + final ISettings settings = ess.getSettings(); + settings.acquireReadLock(); + boolean reported = false; + final List<String> newLines = new ArrayList<String>(); + String pluginName = ""; + String pluginNameLow = ""; + if (!match.equalsIgnoreCase("")) + { + lines.add(_("helpMatching", match)); + } + + for (Plugin p : ess.getServer().getPluginManager().getPlugins()) + { + try + { + final List<String> pluginLines = new ArrayList<String>(); + final PluginDescriptionFile desc = p.getDescription(); + final Map<String, Map<String, Object>> cmds = desc.getCommands(); + pluginName = p.getDescription().getName(); + pluginNameLow = pluginName.toLowerCase(Locale.ENGLISH); + if (pluginNameLow.equals(match)) + { + lines.clear(); + newLines.clear(); + lines.add(_("helpFrom", p.getDescription().getName())); + } + + for (Map.Entry<String, Map<String, Object>> k : cmds.entrySet()) + { + try + { + if (!match.equalsIgnoreCase("") && (!pluginNameLow.contains(match)) && (!k.getKey().toLowerCase(Locale.ENGLISH).contains(match)) + && (!(k.getValue().get(DESCRIPTION) instanceof String + && ((String)k.getValue().get(DESCRIPTION)).toLowerCase(Locale.ENGLISH).contains(match)))) + { + continue; + } + + if (pluginNameLow.contains("essentials")) + { + final String node = "essentials." + k.getKey(); + if (!settings.getData().getCommands().isDisabled(k.getKey()) && user.hasPermission(node)) + { + pluginLines.add(_("helpLine", k.getKey(), k.getValue().get(DESCRIPTION))); + } + } + else + { + if (settings.getData().getCommands().getHelp().isShowNonEssCommandsInHelp()) + { + final Map<String, Object> value = k.getValue(); + Object permissions = null; + if (value.containsKey(PERMISSION)) + { + permissions = value.get(PERMISSION); + } + else if (value.containsKey(PERMISSIONS)) + { + permissions = value.get(PERMISSIONS); + } + if (HelpPermissions.getPermission(pluginNameLow).isAuthorized(user)) + { + pluginLines.add(_("helpLine", k.getKey(), value.get(DESCRIPTION))); + } + else if (permissions instanceof List && !((List<Object>)permissions).isEmpty()) + { + boolean enabled = false; + for (Object o : (List<Object>)permissions) + { + if (o instanceof String && user.hasPermission(o.toString())) + { + enabled = true; + break; + } + } + if (enabled) + { + pluginLines.add(_("helpLine", k.getKey(), value.get(DESCRIPTION))); + } + } + else if (permissions instanceof String && !"".equals(permissions)) + { + if (user.hasPermission(permissions.toString())) + { + pluginLines.add(_("helpLine", k.getKey(), value.get(DESCRIPTION))); + } + } + else + { + if (!settings.getData().getCommands().getHelp().isHidePermissionlessCommands()) + { + pluginLines.add(_("helpLine", k.getKey(), value.get(DESCRIPTION))); + } + } + } + } + } + catch (NullPointerException ex) + { + continue; + } + } + if (!pluginLines.isEmpty()) + { + newLines.addAll(pluginLines); + if (pluginNameLow.equals(match)) + { + break; + } + if (match.equalsIgnoreCase("")) + { + lines.add(_("helpPlugin", pluginName, pluginNameLow)); + } + } + } + catch (NullPointerException ex) + { + continue; + } + catch (Exception ex) + { + if (!reported) + { + logger.log(Level.WARNING, _("commandHelpFailedForPlugin", pluginNameLow), ex); + } + reported = true; + continue; + } + } + lines.addAll(newLines); + } + + @Override + public List<String> getLines() + { + return lines; + } + + @Override + public List<String> getChapters() + { + return chapters; + } + + @Override + public Map<String, Integer> getBookmarks() + { + return bookmarks; + } +} diff --git a/Essentials/src/net/ess3/utils/textreader/IText.java b/Essentials/src/net/ess3/utils/textreader/IText.java new file mode 100644 index 000000000..89e5de19f --- /dev/null +++ b/Essentials/src/net/ess3/utils/textreader/IText.java @@ -0,0 +1,14 @@ +package net.ess3.utils.textreader; + +import java.util.List; +import java.util.Map; + + +public interface IText +{ + List<String> getLines(); + + List<String> getChapters(); + + Map<String, Integer> getBookmarks(); +} diff --git a/Essentials/src/net/ess3/utils/textreader/KeywordReplacer.java b/Essentials/src/net/ess3/utils/textreader/KeywordReplacer.java new file mode 100644 index 000000000..3ec331d7a --- /dev/null +++ b/Essentials/src/net/ess3/utils/textreader/KeywordReplacer.java @@ -0,0 +1,157 @@ +package net.ess3.utils.textreader; + +import net.ess3.utils.DescParseTickFormat; +import net.ess3.api.IEssentials; +import net.ess3.api.IUser; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import lombok.Cleanup; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + + +public class KeywordReplacer implements IText +{ + private final transient IText input; + private final transient List<String> replaced; + private final transient IEssentials ess; + + public KeywordReplacer(final IText input, final CommandSender sender, final IEssentials ess) + { + this.input = input; + this.replaced = new ArrayList<String>(this.input.getLines().size()); + this.ess = ess; + replaceKeywords(sender); + } + + private void replaceKeywords(final CommandSender sender) + { + String displayName, ipAddress, balance, mails, world; + String worlds, online, unique, playerlist, date, time; + String worldTime12, worldTime24, worldDate, plugins; + String userName, address, version; + if (sender instanceof Player) + { + @Cleanup + final IUser user = ess.getUser((Player)sender); + user.acquireReadLock(); + user.setDisplayNick(); + displayName = user.getDisplayName(); + userName = user.getName(); + ipAddress = user.getAddress().getAddress().toString(); + address = user.getAddress().toString(); + balance = Double.toString(user.getMoney()); + mails = Integer.toString(user.getData().getMails() == null ? 0 : user.getData().getMails().size()); + world = user.getLocation() == null || user.getLocation().getWorld() == null ? "" : user.getLocation().getWorld().getName(); + worldTime12 = DescParseTickFormat.format12(user.getWorld() == null ? 0 : user.getWorld().getTime()); + worldTime24 = DescParseTickFormat.format24(user.getWorld() == null ? 0 : user.getWorld().getTime()); + worldDate = DateFormat.getDateInstance(DateFormat.MEDIUM, ess.getI18n().getCurrentLocale()).format(DescParseTickFormat.ticksToDate(user.getWorld() == null ? 0 : user.getWorld().getFullTime())); + } + else + { + displayName = ipAddress = balance = mails = world = worldTime12 = worldTime24 = worldDate = ""; + } + + int playerHidden = 0; + for (Player p : ess.getServer().getOnlinePlayers()) + { + if (ess.getUser(p).isHidden()) + { + playerHidden++; + } + } + online = Integer.toString(ess.getServer().getOnlinePlayers().length - playerHidden); + unique = Integer.toString(ess.getUserMap().getUniqueUsers()); + + final StringBuilder worldsBuilder = new StringBuilder(); + for (World w : ess.getServer().getWorlds()) + { + if (worldsBuilder.length() > 0) + { + worldsBuilder.append(", "); + } + worldsBuilder.append(w.getName()); + } + worlds = worldsBuilder.toString(); + + final StringBuilder playerlistBuilder = new StringBuilder(); + for (Player p : ess.getServer().getOnlinePlayers()) + { + if (ess.getUser(p).isHidden()) + { + continue; + } + if (playerlistBuilder.length() > 0) + { + playerlistBuilder.append(", "); + } + playerlistBuilder.append(p.getDisplayName()); + } + playerlist = playerlistBuilder.toString(); + + final StringBuilder pluginlistBuilder = new StringBuilder(); + for (Plugin p : ess.getServer().getPluginManager().getPlugins()) + { + if (pluginlistBuilder.length() > 0) + { + pluginlistBuilder.append(", "); + } + pluginlistBuilder.append(p.getDescription().getName()); + } + plugins = pluginlistBuilder.toString(); + + date = DateFormat.getDateInstance(DateFormat.MEDIUM, ess.getI18n().getCurrentLocale()).format(new Date()); + time = DateFormat.getTimeInstance(DateFormat.MEDIUM, ess.getI18n().getCurrentLocale()).format(new Date()); + + version = ess.getServer().getVersion(); + + for (int i = 0; i < input.getLines().size(); i++) + { + String line = input.getLines().get(i); + + line = line.replace("{PLAYER}", displayName); + line = line.replace("{DISPLAYNAME}", displayName); + line = line.replace("{USERNAME}", displayName); + line = line.replace("{IP}", ipAddress); + line = line.replace("{ADDRESS}", ipAddress); + line = line.replace("{BALANCE}", balance); + line = line.replace("{MAILS}", mails); + line = line.replace("{WORLD}", world); + line = line.replace("{ONLINE}", online); + line = line.replace("{UNIQUE}", unique); + line = line.replace("{WORLDS}", worlds); + line = line.replace("{PLAYERLIST}", playerlist); + line = line.replace("{TIME}", time); + line = line.replace("{DATE}", date); + line = line.replace("{WORLDTIME12}", worldTime12); + line = line.replace("{WORLDTIME24}", worldTime24); + line = line.replace("{WORLDDATE}", worldDate); + line = line.replace("{PLUGINS}", plugins); + line = line.replace("{VERSION}", version); + replaced.add(line); + } + } + + @Override + public List<String> getLines() + { + return replaced; + } + + @Override + public List<String> getChapters() + { + return input.getChapters(); + } + + @Override + public Map<String, Integer> getBookmarks() + { + return input.getBookmarks(); + } +} diff --git a/Essentials/src/net/ess3/utils/textreader/SimpleTextInput.java b/Essentials/src/net/ess3/utils/textreader/SimpleTextInput.java new file mode 100644 index 000000000..8d392448e --- /dev/null +++ b/Essentials/src/net/ess3/utils/textreader/SimpleTextInput.java @@ -0,0 +1,35 @@ +package net.ess3.utils.textreader; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + + +public class SimpleTextInput implements IText +{ + private final transient List<String> lines = new ArrayList<String>(); + + public SimpleTextInput (final String input) { + lines.add(input); + } + + @Override + public List<String> getLines() + { + return lines; + } + + @Override + public List<String> getChapters() + { + return Collections.emptyList(); + } + + @Override + public Map<String, Integer> getBookmarks() + { + return Collections.emptyMap(); + } + +} diff --git a/Essentials/src/net/ess3/utils/textreader/SimpleTextPager.java b/Essentials/src/net/ess3/utils/textreader/SimpleTextPager.java new file mode 100644 index 000000000..ea70010b6 --- /dev/null +++ b/Essentials/src/net/ess3/utils/textreader/SimpleTextPager.java @@ -0,0 +1,31 @@ +package net.ess3.utils.textreader; + +import org.bukkit.command.CommandSender; + + +public class SimpleTextPager +{ + private final transient IText text; + + public SimpleTextPager(final IText text) + { + this.text = text; + } + + public void showPage(final CommandSender sender) + { + for (String line : text.getLines()) + { + sender.sendMessage(line); + } + } + + public String getString(int line) + { + if (text.getLines().size() < line) + { + return null; + } + return text.getLines().get(line); + } +} diff --git a/Essentials/src/net/ess3/utils/textreader/TextInput.java b/Essentials/src/net/ess3/utils/textreader/TextInput.java new file mode 100644 index 000000000..20fecc255 --- /dev/null +++ b/Essentials/src/net/ess3/utils/textreader/TextInput.java @@ -0,0 +1,149 @@ +package net.ess3.utils.textreader; + +import net.ess3.utils.Util; +import net.ess3.api.IEssentials; +import net.ess3.api.IUser; +import net.ess3.api.InvalidNameException; +import java.io.*; +import java.lang.ref.SoftReference; +import java.util.*; +import java.util.logging.Level; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + + +public class TextInput implements IText +{ + private final transient List<String> lines; + private final transient List<String> chapters; + private final transient Map<String, Integer> bookmarks; + private final transient long lastChange; + private final static HashMap<String, SoftReference<TextInput>> cache = new HashMap<String, SoftReference<TextInput>>(); + + public TextInput(final CommandSender sender, final String filename, final boolean createFile, final IEssentials ess) throws IOException + { + + File file = null; + if (sender instanceof Player) + { + try + { + final IUser user = ess.getUser((Player)sender); + file = new File(ess.getDataFolder(), filename + "_" + Util.sanitizeFileName(user.getName()) + ".txt"); + if (!file.exists()) + { + file = new File(ess.getDataFolder(), filename + "_" + Util.sanitizeFileName(ess.getRanks().getMainGroup(user)) + ".txt"); + } + } + catch (InvalidNameException ex) + { + Bukkit.getLogger().log(Level.WARNING, ex.getMessage(), ex); + } + } + if (file == null || !file.exists()) + { + file = new File(ess.getDataFolder(), filename + ".txt"); + } + if (file.exists()) + { + lastChange = file.lastModified(); + boolean readFromfile; + synchronized (cache) + { + final SoftReference<TextInput> inputRef = cache.get(file.getName()); + TextInput input; + if (inputRef == null || (input = inputRef.get()) == null || input.lastChange < lastChange) + { + lines = new ArrayList<String>(); + chapters = new ArrayList<String>(); + bookmarks = new HashMap<String, Integer>(); + cache.put(file.getName(), new SoftReference<TextInput>(this)); + readFromfile = true; + } + else + { + lines = Collections.unmodifiableList(input.getLines()); + chapters = Collections.unmodifiableList(input.getChapters()); + bookmarks = Collections.unmodifiableMap(input.getBookmarks()); + readFromfile = false; + } + } + if (readFromfile) + { + final BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); + try + { + int lineNumber = 0; + while (bufferedReader.ready()) + { + final String line = bufferedReader.readLine(); + if (line == null) + { + break; + } + if (line.length() > 0 && line.charAt(0) == '#') + { + bookmarks.put(line.substring(1).toLowerCase(Locale.ENGLISH).replaceAll("&[0-9a-fk]", ""), lineNumber); + chapters.add(line.substring(1).replace('&', '§').replace("§§", "&")); + } + lines.add(line.replace('&', '§').replace("§§", "&")); + lineNumber++; + } + } + finally + { + bufferedReader.close(); + } + } + } + else + { + lastChange = 0; + lines = Collections.emptyList(); + chapters = Collections.emptyList(); + bookmarks = Collections.emptyMap(); + if (createFile) + { + final InputStream input = ess.getResource(filename + ".txt"); + final OutputStream output = new FileOutputStream(file); + try + { + final byte[] buffer = new byte[1024]; + int length = input.read(buffer); + while (length > 0) + { + output.write(buffer, 0, length); + length = input.read(buffer); + } + } + finally + { + if(output != null) + output.close(); + if(input != null) + input.close(); + } + throw new FileNotFoundException("File " + filename + ".txt does not exist. Creating one for you."); + } + } + } + + @Override + public List<String> getLines() + { + return lines; + } + + @Override + public List<String> getChapters() + { + return chapters; + } + + @Override + public Map<String, Integer> getBookmarks() + { + return bookmarks; + } +} diff --git a/Essentials/src/net/ess3/utils/textreader/TextPager.java b/Essentials/src/net/ess3/utils/textreader/TextPager.java new file mode 100644 index 000000000..18b662be5 --- /dev/null +++ b/Essentials/src/net/ess3/utils/textreader/TextPager.java @@ -0,0 +1,200 @@ +package net.ess3.utils.textreader; + +import net.ess3.I18n; +import static net.ess3.I18n._; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.bukkit.command.CommandSender; + + +public class TextPager +{ + private final transient IText text; + private final transient boolean onePage; + + public TextPager(final IText text) + { + this(text, false); + } + + public TextPager(final IText text, final boolean onePage) + { + this.text = text; + this.onePage = onePage; + } + + public void showPage(final String pageStr, final String chapterPageStr, final String commandName, final CommandSender sender) + { + List<String> lines = text.getLines(); + List<String> chapters = text.getChapters(); + Map<String, Integer> bookmarks = text.getBookmarks(); + + if (bookmarks.isEmpty()) + { + int page = 1; + try + { + page = Integer.parseInt(pageStr); + } + catch (Exception ex) + { + page = 1; + } + if (page < 1) + { + page = 1; + } + + final int start = onePage ? 0 : (page - 1) * 9; + final int pages = lines.size() / 9 + (lines.size() % 9 > 0 ? 1 : 0); + if (!onePage) + { + StringBuilder content = new StringBuilder(); + final String[] title = commandName.split(" ", 2); + if (title.length > 1) + { + content.append(I18n.capitalCase(title[0])).append(": "); + content.append(title[1]); + } + else if (chapterPageStr != null) + { + content.append(I18n.capitalCase(commandName)).append(": "); + content.append(chapterPageStr); + } + else + { + content.append(I18n.capitalCase(commandName)); + } + sender.sendMessage(_("infoPages", page, pages, content)); + } + for (int i = start; i < lines.size() && i < start + (onePage ? 20 : 9); i++) + { + sender.sendMessage(lines.get(i)); + } + if (!onePage && page < pages) + { + sender.sendMessage(_("readNextPage", commandName, page + 1)); + } + return; + } + + if (pageStr == null || pageStr.isEmpty() || pageStr.matches("[0-9]+")) + { + if (lines.get(0).startsWith("#")) + { + if (onePage) + { + return; + } + sender.sendMessage(_("infoChapter")); + final StringBuilder sb = new StringBuilder(); + boolean first = true; + for (String string : chapters) + { + if (!first) + { + sb.append(", "); + } + first = false; + sb.append(string); + } + sender.sendMessage(sb.toString()); + return; + } + else + { + int page = 1; + try + { + page = Integer.parseInt(pageStr); + } + catch (Exception ex) + { + page = 1; + } + if (page < 1) + { + page = 1; + } + + int start = onePage ? 0 : (page - 1) * 9; + int end; + for (end = 0; end < lines.size(); end++) + { + String line = lines.get(end); + if (line.startsWith("#")) + { + break; + } + } + + int pages = end / 9 + (end % 9 > 0 ? 1 : 0); + if (!onePage) + { + + sender.sendMessage(_("infoPages", page, pages, I18n.capitalCase(commandName))); + } + for (int i = start; i < end && i < start + (onePage ? 20 : 9); i++) + { + sender.sendMessage(lines.get(i)); + } + if (!onePage && page < pages) + { + sender.sendMessage(_("readNextPage", commandName, page + 1)); + } + return; + } + } + + int chapterpage = 0; + if (chapterPageStr != null) + { + try + { + chapterpage = Integer.parseInt(chapterPageStr) - 1; + } + catch (Exception ex) + { + chapterpage = 0; + } + if (chapterpage < 0) + { + chapterpage = 0; + } + } + + if (!bookmarks.containsKey(pageStr.toLowerCase(Locale.ENGLISH))) + { + sender.sendMessage(_("infoUnknownChapter")); + return; + } + final int chapterstart = bookmarks.get(pageStr.toLowerCase(Locale.ENGLISH)) + 1; + int chapterend; + for (chapterend = chapterstart; chapterend < lines.size(); chapterend++) + { + final String line = lines.get(chapterend); + if (line.length() > 0 && line.charAt(0) == '#') + { + break; + } + } + final int start = chapterstart + (onePage ? 0 : chapterpage * 9); + + final int page = chapterpage + 1; + final int pages = (chapterend - chapterstart) / 9 + ((chapterend - chapterstart) % 9 > 0 ? 1 : 0); + if (!onePage) + { + sender.sendMessage(_("infoChapterPages", pageStr, page, pages)); + } + for (int i = start; i < chapterend && i < start + (onePage ? 20 : 9); i++) + { + sender.sendMessage(lines.get(i)); + } + if (!onePage && page < pages) + { + sender.sendMessage(_("readNextPage", commandName, pageStr + " " + (page + 1))); + } + } +} |