summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsnowleo <schneeleo@gmail.com>2011-08-08 17:00:04 +0200
committersnowleo <schneeleo@gmail.com>2011-08-08 17:00:04 +0200
commita109134b92893ad98a6a8dabf32c0e42a6757806 (patch)
tree14c3b8c8e4604bf54fadd6b296daf56608d0886a
parent69d3921a6ae566455387bf39a7de648d0c823c6a (diff)
downloadEssentials-a109134b92893ad98a6a8dabf32c0e42a6757806.tar
Essentials-a109134b92893ad98a6a8dabf32c0e42a6757806.tar.gz
Essentials-a109134b92893ad98a6a8dabf32c0e42a6757806.tar.lz
Essentials-a109134b92893ad98a6a8dabf32c0e42a6757806.tar.xz
Essentials-a109134b92893ad98a6a8dabf32c0e42a6757806.zip
Part of oloflarsson new time command
Semi complete awesome time command. This is missing: Help text, I18N.
-rwxr-xr-xEssentials/src/com/earth2me/essentials/DescParseTickFormat.java276
-rwxr-xr-xEssentials/src/com/earth2me/essentials/commands/Commandptime.java223
-rwxr-xr-x[-rw-r--r--]Essentials/src/com/earth2me/essentials/commands/Commandtime.java199
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());
}
}