From a109134b92893ad98a6a8dabf32c0e42a6757806 Mon Sep 17 00:00:00 2001 From: snowleo Date: Mon, 8 Aug 2011 17:00:04 +0200 Subject: [PATCH] Part of oloflarsson new time command Semi complete awesome time command. This is missing: Help text, I18N. --- .../essentials/DescParseTickFormat.java | 276 ++++++++++++++++++ .../essentials/commands/Commandptime.java | 223 ++++++++++++++ .../essentials/commands/Commandtime.java | 229 +++++++++------ 3 files changed, 646 insertions(+), 82 deletions(-) create mode 100755 Essentials/src/com/earth2me/essentials/DescParseTickFormat.java create mode 100755 Essentials/src/com/earth2me/essentials/commands/Commandptime.java mode change 100644 => 100755 Essentials/src/com/earth2me/essentials/commands/Commandtime.java diff --git a/Essentials/src/com/earth2me/essentials/DescParseTickFormat.java b/Essentials/src/com/earth2me/essentials/DescParseTickFormat.java new file mode 100755 index 000000000..93f57135d --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/DescParseTickFormat.java @@ -0,0 +1,276 @@ +package com.earth2me.essentials; + +import com.earth2me.essentials.commands.Commandtime; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 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 class DescParseTickFormat { + + // ============================================ + // First some information vars. TODO: Should this be in a config file? + // -------------------------------------------- + + public static final Map nameToTicks = new LinkedHashMap(); + public static final Set resetAliases = new HashSet(); + + 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 { + + nameToTicks.put("sunrise", 22000); + nameToTicks.put("rise", 22000); + nameToTicks.put("dawn", 22000); + + nameToTicks.put("daystart", 0); + nameToTicks.put("day", 0); + + nameToTicks.put("morning", 3000); + + nameToTicks.put("midday", 6000); + nameToTicks.put("noon", 6000); + + nameToTicks.put("afternoon", 9000); + + nameToTicks.put("sunset", 12000); + nameToTicks.put("set", 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"); + } + + // ============================================ + // PARSE. From describing String to int + // -------------------------------------------- + + public static long parse(String desc) throws NumberFormatException + { + Long ret; + + // Only look at alphanumeric and lowercase + desc = desc.toLowerCase().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().replaceAll("[^0-9]", ""); + + if (desc.length() != 4) + { + throw new NumberFormatException(); + } + + int hours = Integer.parseInt(desc.substring(0, 2)); + 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; + if (desc.endsWith("pm")) + { + hours += 12; + } + + desc = desc.toLowerCase().replaceAll("[^0-9]", ""); + + if (desc.length() > 4) + { + throw new NumberFormatException(); + } + + if (desc.length() == 4) + { + hours += Integer.parseInt(desc.substring(0, 2)); + minutes += Integer.parseInt(desc.substring(2, 4)); + } + else if (desc.length() == 3) + { + hours += Integer.parseInt(desc.substring(0, 1)); + minutes += Integer.parseInt(desc.substring(1, 3)); + } + else if (desc.length() == 2) + { + hours += Integer.parseInt(desc.substring(0, 2)); + } + else if (desc.length() == 1) + { + hours += Integer.parseInt(desc.substring(0, 1)); + } + else + { + throw new NumberFormatException(); + } + + return hoursMinutesToTicks(hours, minutes); + } + + public static long hoursMinutesToTicks(int hours, int minutes) + { + long ret = ticksAtMidnight; + ret += (hours - 1) * ticksPerHour; + + ret += (minutes / 60.0) * ticksPerHour; + + ret %= ticksPerDay; + return ret; + } + + public static long parseAlias(String desc) throws NumberFormatException + { + Integer ret = nameToTicks.get(desc); + if ( ret == null) + { + throw new NumberFormatException(); + } + + return ret; + } + + public static boolean meansReset(String desc) + { + return resetAliases.contains(desc); + } + + // ============================================ + // FORMAT. From int to describing String + // -------------------------------------------- + + public static String format(long ticks) + { + StringBuilder msg = new StringBuilder(); + msg.append(Commandtime.colorHighlight1); + msg.append(format24(ticks)); + msg.append(Commandtime.colorDefault); + msg.append(" or "); + msg.append(Commandtime.colorHighlight1); + msg.append(format12(ticks)); + msg.append(Commandtime.colorDefault); + msg.append(" or "); + msg.append(Commandtime.colorHighlight1); + msg.append(formatTicks(ticks)); + return msg.toString(); + } + + public static String formatTicks(long ticks) + { + return ""+ticks%ticksPerDay+"ticks"; + } + + public static String format24(long ticks) + { + return formatDateFormat(ticks, SDFTwentyFour); + } + + public static String format12(long ticks) + { + return formatDateFormat(ticks, SDFTwelve); + } + + public static String formatDateFormat(long ticks, SimpleDateFormat format) + { + 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? + long days = ticks / ticksPerDay; + ticks = ticks - days * ticksPerDay; + + // How many hours on the last day? + long hours = ticks / ticksPerHour; + ticks = ticks - hours * ticksPerHour; + + // How many minutes on the last day? + long minutes = (long) Math.floor(ticks / ticksPerMinute); + double dticks = ticks - minutes*ticksPerMinute; + + // How many seconds on the last day? + long seconds = (long) Math.floor(dticks / ticksPerSecond); + + // Now we create an english GMT calendar (We wan't no daylight savings) + 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/com/earth2me/essentials/commands/Commandptime.java b/Essentials/src/com/earth2me/essentials/commands/Commandptime.java new file mode 100755 index 000000000..0662c9b85 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/commands/Commandptime.java @@ -0,0 +1,223 @@ +package com.earth2me.essentials.commands; + +import com.earth2me.essentials.DescParseTickFormat; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import com.earth2me.essentials.User; +import java.util.*; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + + +public class Commandptime extends EssentialsCommand +{ + // TODO: I suggest that the chat colors be centralized in the config file. + public static final ChatColor colorDefault = ChatColor.YELLOW; + public static final ChatColor colorChrome = ChatColor.GOLD; + public static final ChatColor colorLogo = ChatColor.GREEN; + public static final ChatColor colorHighlight1 = ChatColor.AQUA; + public static final ChatColor colorBad = ChatColor.RED; + + public Commandptime() + { + super("ptime"); + } + + @Override + public void run(final Server server, final CommandSender sender, final String commandLabel, final String[] args) throws Exception + { + // Which Players(s) / Users(s) are we interested in? + String userSelector = null; + if (args.length == 2) + { + userSelector = args[1]; + } + Set users = getUsers(server, sender, userSelector); + + // If no arguments we are reading the time + if (args.length == 0) + { + // TODO do we need to check for the essentials.time permission? Or is that tested for us already. + getUsersTime(sender, users); + return; + } + + User user = ess.getUser(sender); + if ( user != null && ! user.isAuthorized("essentials.time.player")) + { + // TODO should not be hardcoded !! + sender.sendMessage(colorBad + "You are no authorized to set PlayerTime"); + return; // TODO: How to not just die silently? in a good way?? + } + + Long ticks; + // Parse the target time int ticks from args[0] + if (DescParseTickFormat.meansReset(args[0])) + { + ticks = null; + } + else + { + try + { + ticks = DescParseTickFormat.parse(args[0]); + } + catch (NumberFormatException e) + { + // TODO: Display an error with help included... on how to specify the time + sender.sendMessage(colorBad + "Unknown time descriptor... brlalidididiablidadadibibibiiba!! TODO"); + return; + } + } + + setUsersTime(sender, users, ticks); + } + + + /** + * Used to get the time and inform + */ + private void getUsersTime(CommandSender sender, Collection users) + { + if (users.size() == 1) + { + Iterator iter = users.iterator(); + User user = iter.next(); + + if (user.isPlayerTimeRelative()) + { + sender.sendMessage(colorDefault + user.getName() + "'s time is normal. Time is the same as on the server."); + } + else + { + sender.sendMessage(colorDefault + user.getName() + "'s time is fixed to: "+DescParseTickFormat.format(user.getPlayerTime())); + } + return; + } + + sender.sendMessage(colorDefault + "These players have fixed time:"); + + for (User user : users) + { + if ( ! user.isPlayerTimeRelative()) + { + sender.sendMessage(colorDefault + user.getName() + ": "+DescParseTickFormat.format(user.getPlayerTime())); + } + } + return; + } + + /** + * Used to set the time and inform of the change + */ + private void setUsersTime(CommandSender sender, Collection users, Long ticks) + { + // Update the time + if (ticks == null) + { + // Reset + for (User user : users) + { + user.resetPlayerTime(); + } + } + else + { + // Set + for (User user : users) + { + user.setPlayerTime(ticks, false); + } + } + + + // Inform the sender of the change + sender.sendMessage(""); + StringBuilder msg = new StringBuilder(); + if (ticks == null) + { + sender.sendMessage(colorDefault + "The PlayerTime was reset for:"); + } + else + { + sender.sendMessage(colorDefault + "The PlayerTime was fixed to:"); + sender.sendMessage(DescParseTickFormat.format(ticks)); + msg.append(colorDefault); + msg.append("For: "); + } + + boolean first = true; + for (User user : users) + { + if ( ! first) + { + msg.append(colorDefault); + msg.append(", "); + } + else + { + first = false; + } + + msg.append(colorHighlight1); + msg.append(user.getName()); + } + + sender.sendMessage(msg.toString()); + } + + /** + * Used to parse an argument of the type "users(s) selector" + */ + private Set getUsers(Server server, CommandSender sender, String selector) throws Exception + { + Set users = new TreeSet(new UserNameComparator()); + Player[] players; + // If there is no selector we want the sender itself. Or all users if sender isn't a user. + if (selector == null) + { + User user = ess.getUser(sender); + if (user == null) + { + users.addAll(ess.getAllOnlineUsers().values()); + } + else + { + users.add(user); + } + return users; + } + + // Try to find the user with name = selector + User user = null; + List matchedPlayers = server.matchPlayer(selector); + if (matchedPlayers.size() > 0) + { + user = ess.getUser(matchedPlayers.get(0)); + } + + if (user != null) + { + users.add(user); + } + // If that fails, Is the argument something like "*" or "all"? + else if (selector.equalsIgnoreCase("*") || selector.equalsIgnoreCase("all")) + { + users.addAll(ess.getAllOnlineUsers().values()); + } + // We failed to understand the world target... + else + { + throw new Exception("Could not find the player(s) \""+selector+"\""); + } + + return users; + } +} + +class UserNameComparator implements Comparator { + public int compare(User a, User b) + { + return a.getName().compareTo(b.getName()); + } +} diff --git a/Essentials/src/com/earth2me/essentials/commands/Commandtime.java b/Essentials/src/com/earth2me/essentials/commands/Commandtime.java old mode 100644 new mode 100755 index c823e84af..e895074e5 --- a/Essentials/src/com/earth2me/essentials/commands/Commandtime.java +++ b/Essentials/src/com/earth2me/essentials/commands/Commandtime.java @@ -1,113 +1,178 @@ package com.earth2me.essentials.commands; +import com.earth2me.essentials.DescParseTickFormat; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.command.CommandSender; import com.earth2me.essentials.User; -import com.earth2me.essentials.Util; +import java.util.*; +import org.bukkit.ChatColor; public class Commandtime extends EssentialsCommand { + // TODO: I suggest that the chat colors be centralized in the config file. + public static final ChatColor colorDefault = ChatColor.YELLOW; + public static final ChatColor colorChrome = ChatColor.GOLD; + public static final ChatColor colorLogo = ChatColor.GREEN; + public static final ChatColor colorHighlight1 = ChatColor.AQUA; + public static final ChatColor colorBad = ChatColor.RED; + public Commandtime() { super("time"); } @Override - public void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception + public void run(final Server server, final CommandSender sender, final String commandLabel, final String[] args) throws Exception { - if (args.length < 1) + // Which World(s) are we interested in? + String worldSelector = null; + if (args.length == 2) { - throw new NotEnoughArgumentsException(); + worldSelector = args[1]; } - if (args.length < 2) + Set worlds = getWorlds(server, sender, worldSelector); + + // If no arguments we are reading the time + if (args.length == 0) { - if (user.isAuthorized("essentials.time.world")) - { - final World world = user.getWorld(); + // TODO do we need to check for the essentials.time permission? Or is that tested for us already. + getWorldsTime(sender, worlds); + return; + } - charge(user); - setWorldTime(world, args[0]); + User user = ess.getUser(sender); + if ( user != null && ! user.isAuthorized("essentials.time.world")) + { + // TODO should not be hardcoded !! + sender.sendMessage(colorBad + "You are no authorized to set the time"); + return; // TODO: How to not just die silently? in a good way?? + } + + // Parse the target time int ticks from args[0] + long ticks; + try + { + ticks = DescParseTickFormat.parse(args[0]); + } + catch (NumberFormatException e) + { + // TODO: Display an error with help included... on how to specify the time + sender.sendMessage(colorBad + "Unknown time descriptor... brlalidididiablidadadibibibiiba!! TODO"); + return; + } + + setWorldsTime(sender, worlds, ticks); + } + + /** + * Used to get the time and inform + */ + private void getWorldsTime(CommandSender sender, Collection worlds) + { + // TODO do we need to check for the essentials.time permission? Or is that tested for us already. + if (worlds.size() == 1) + { + Iterator iter = worlds.iterator(); + sender.sendMessage(DescParseTickFormat.format(iter.next().getTime())); + return; + } + + for (World world : worlds) + { + sender.sendMessage(colorDefault + world.getName()+": " + DescParseTickFormat.format(world.getTime())); + } + return; + } + + /** + * Used to set the time and inform of the change + */ + private void setWorldsTime(CommandSender sender, Collection worlds, long ticks) + { + // Update the time + for (World world : worlds) + { + world.setTime(ticks); + } + + // Inform the sender of the change + sender.sendMessage(""); + sender.sendMessage(colorDefault + "The time was set to"); + sender.sendMessage(DescParseTickFormat.format(ticks)); + + StringBuilder msg = new StringBuilder(); + msg.append(colorDefault); + msg.append("In "); + boolean first = true; + for (World world : worlds) + { + if ( ! first) + { + msg.append(colorDefault); + msg.append(", "); } else { - charge(user); - setPlayerTime(user, args[0]); + first = false; } + + msg.append(colorHighlight1); + msg.append(world.getName()); } + + sender.sendMessage(msg.toString()); + } + + /** + * Used to parse an argument of the type "world(s) selector" + */ + private Set getWorlds(Server server, CommandSender sender, String selector) throws Exception + { + Set worlds = new TreeSet(new WorldNameComparator()); + + // If there is no selector we want the world the user is currently in. Or all worlds if it isn't a user. + if (selector == null) + { + User user = ess.getUser(sender); + if (user == null) + { + worlds.addAll(server.getWorlds()); + } + else + { + worlds.add(user.getWorld()); + } + return worlds; + } + + // Try to find the world with name = selector + World world = server.getWorld(selector); + if (world != null) + { + worlds.add(world); + } + // If that fails, Is the argument something like "*" or "all"? + else if (selector.equalsIgnoreCase("*") || selector.equalsIgnoreCase("all")) + { + worlds.addAll(server.getWorlds()); + } + // We failed to understand the world target... else { - if (user.isAuthorized("essentials.time.others")) - { - User u = getPlayer(server, args, 1); - charge(user); - setPlayerTime(u, args[0]); - } + throw new Exception("Could not find the world(s) \""+selector+"\""); } - } - - @Override - public void run(final Server server, final CommandSender sender, final String commandLabel, final String[] args) throws Exception - { - if (args.length < 1) - { - throw new NotEnoughArgumentsException(); - } - if (args.length < 2) - { - for (World world : server.getWorlds()) - { - setWorldTime(world, args[0]); - } - } - else - { - User u = getPlayer(server, args, 1); - setPlayerTime(u, args[0]); - } - - sender.sendMessage(Util.i18n("timeSet")); - } - - private void setWorldTime(final World world, final String timeString) throws Exception - { - long time = world.getTime(); - time -= time % 24000; - if ("day".equalsIgnoreCase(timeString)) - { - world.setTime(time + 24000); - return; - } - if ("night".equalsIgnoreCase(timeString)) - { - world.setTime(time + 37700); - return; - } - throw new Exception(Util.i18n("onlyDayNight")); - } - - private void setPlayerTime(final User user, final String timeString) throws Exception - { - long time = user.getPlayerTime(); - time -= time % 24000; - if ("day".equalsIgnoreCase(timeString)) - { - final World world = user.getWorld(); - user.setPlayerTime(time + 24000 - world.getTime(), true); - return; - } - if ("night".equalsIgnoreCase(timeString)) - { - final World world = user.getWorld(); - user.setPlayerTime(time + 37700 - world.getTime(), true); - return; - } - if ("reset".equalsIgnoreCase(timeString)) - { - user.resetPlayerTime(); - return; - } - throw new Exception(Util.i18n("onlyDayNight")); + + return worlds; + } +} + + + +class WorldNameComparator implements Comparator { + public int compare(World a, World b) + { + return a.getName().compareTo(b.getName()); } }