diff options
-rwxr-xr-x | Essentials/src/com/earth2me/essentials/DescParseTickFormat.java | 276 | ||||
-rwxr-xr-x | Essentials/src/com/earth2me/essentials/commands/Commandptime.java | 223 | ||||
-rwxr-xr-x[-rw-r--r--] | Essentials/src/com/earth2me/essentials/commands/Commandtime.java | 199 |
3 files changed, 631 insertions, 67 deletions
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<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 { + + 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<User> 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<User> users) + { + if (users.size() == 1) + { + Iterator<User> 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<User> 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<User> getUsers(Server server, CommandSender sender, String selector) throws Exception + { + Set<User> users = new TreeSet<User>(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<Player> 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<User> { + 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 index c823e84af..e895074e5 100644..100755 --- 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<World> 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(); - - charge(user); - setWorldTime(world, args[0]); - } - else - { - charge(user); - setPlayerTime(user, args[0]); - } - } - else - { - if (user.isAuthorized("essentials.time.others")) - { - User u = getPlayer(server, args, 1); - charge(user); - setPlayerTime(u, args[0]); - } + // TODO do we need to check for the essentials.time permission? Or is that tested for us already. + getWorldsTime(sender, worlds); + return; } - } - @Override - public void run(final Server server, final CommandSender sender, final String commandLabel, final String[] args) throws Exception - { - if (args.length < 1) + User user = ess.getUser(sender); + if ( user != null && ! user.isAuthorized("essentials.time.world")) { - throw new NotEnoughArgumentsException(); + // 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?? } - if (args.length < 2) + + // Parse the target time int ticks from args[0] + long ticks; + try { - for (World world : server.getWorlds()) - { - setWorldTime(world, args[0]); - } + ticks = DescParseTickFormat.parse(args[0]); } - else + catch (NumberFormatException e) { - User u = getPlayer(server, args, 1); - setPlayerTime(u, args[0]); + // TODO: Display an error with help included... on how to specify the time + sender.sendMessage(colorBad + "Unknown time descriptor... brlalidididiablidadadibibibiiba!! TODO"); + return; } - sender.sendMessage(Util.i18n("timeSet")); + setWorldsTime(sender, worlds, ticks); } - - private void setWorldTime(final World world, final String timeString) throws Exception + + /** + * Used to get the time and inform + */ + private void getWorldsTime(CommandSender sender, Collection<World> worlds) { - long time = world.getTime(); - time -= time % 24000; - if ("day".equalsIgnoreCase(timeString)) + // TODO do we need to check for the essentials.time permission? Or is that tested for us already. + if (worlds.size() == 1) { - world.setTime(time + 24000); + Iterator<World> iter = worlds.iterator(); + sender.sendMessage(DescParseTickFormat.format(iter.next().getTime())); return; } - if ("night".equalsIgnoreCase(timeString)) + + for (World world : worlds) { - world.setTime(time + 37700); - return; + sender.sendMessage(colorDefault + world.getName()+": " + DescParseTickFormat.format(world.getTime())); } - throw new Exception(Util.i18n("onlyDayNight")); + return; } - - private void setPlayerTime(final User user, final String timeString) throws Exception + + /** + * Used to set the time and inform of the change + */ + private void setWorldsTime(CommandSender sender, Collection<World> worlds, long ticks) { - long time = user.getPlayerTime(); - time -= time % 24000; - if ("day".equalsIgnoreCase(timeString)) + // Update the time + for (World world : worlds) { - final World world = user.getWorld(); - user.setPlayerTime(time + 24000 - world.getTime(), true); - return; + world.setTime(ticks); } - if ("night".equalsIgnoreCase(timeString)) + + // 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) { - final World world = user.getWorld(); - user.setPlayerTime(time + 37700 - world.getTime(), true); - return; + if ( ! first) + { + msg.append(colorDefault); + msg.append(", "); + } + else + { + first = false; + } + + msg.append(colorHighlight1); + msg.append(world.getName()); } - if ("reset".equalsIgnoreCase(timeString)) + + sender.sendMessage(msg.toString()); + } + + /** + * Used to parse an argument of the type "world(s) selector" + */ + private Set<World> getWorlds(Server server, CommandSender sender, String selector) throws Exception + { + Set<World> worlds = new TreeSet<World>(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.resetPlayerTime(); - return; + User user = ess.getUser(sender); + if (user == null) + { + worlds.addAll(server.getWorlds()); + } + else + { + worlds.add(user.getWorld()); + } + return worlds; } - throw new Exception(Util.i18n("onlyDayNight")); + + // 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 + { + throw new Exception("Could not find the world(s) \""+selector+"\""); + } + + return worlds; + } +} + + + +class WorldNameComparator implements Comparator<World> { + public int compare(World a, World b) + { + return a.getName().compareTo(b.getName()); } } |