/*
* CommandBook
* Copyright (C) 2011 sk89q <http://www.sk89q.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.commandbook.time;
import com.google.common.collect.Lists;
import com.sk89q.commandbook.CommandBook;
import com.sk89q.commandbook.util.ChatUtil;
import com.sk89q.commandbook.util.InputUtil;
import com.sk89q.commandbook.util.entity.player.PlayerUtil;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.zachsthings.libcomponents.ComponentInformation;
import com.zachsthings.libcomponents.bukkit.BukkitComponent;
import com.zachsthings.libcomponents.config.ConfigurationBase;
import com.zachsthings.libcomponents.config.Setting;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import java.util.HashMap;
import java.util.Map;
/**
* TimeComponent contains commands and functions related to time management. These include
*/
@ComponentInformation(friendlyName = "Time Control", desc = "Commands to manage and lock time for a world.")
public class TimeComponent extends BukkitComponent implements Listener {
/**
* A Map of time locker tasks for worlds.
*/
protected final Map<String, Integer> tasks = new HashMap<String, Integer>();
/**
* A Map of world names to time values.
*/
protected final Map<String, Integer> lockedTimes = new HashMap<String, Integer>();
/**
* This Component's configuration
*/
protected LocalConfiguration config;
@Override
public void enable() {
config = configure(new LocalConfiguration());
if (config.timeLockDelay == 0) {
config.timeLockDelay = 20;
saveConfig(config);
}
configureWorldLocks();
registerCommands(Commands.class);
CommandBook.registerEvents(this);
}
private void configureWorldLocks() {
if (config.timeLocks != null) {
for (Map.Entry<String, Object> entry : config.timeLocks.entrySet()) {
int time = 0;
try {
time = InputUtil.TimeParser.matchMCWorldTime(String.valueOf(entry.getValue()));
} catch (CommandException e) {
CommandBook.logger().warning("Time lock: Failed to parse time '"
+ entry.getValue() + "'");
continue;
}
lockedTimes.put(entry.getKey(), time);
World world = CommandBook.server().getWorld(entry.getKey());
if (world == null) {
CommandBook.logger().info("Could not time-lock unknown world '"
+ entry.getKey() + "'");
continue;
}
world.setTime(time);
lock(world);
CommandBook.logger().info("Time locked to '"
+ ChatUtil.getTimeString(time) + "' for world '"
+ world.getName() + "'");
}
}
}
@Override
public void reload() {
super.reload();
configureWorldLocks();
}
private static class LocalConfiguration extends ConfigurationBase {
@Setting("time-lock") public Map<String, Object> timeLocks;
@Setting("time-lock-delay") public int timeLockDelay = 20;
}
/**
* Called when a World is loaded.
*/
@EventHandler
public void onWorldLoad(WorldLoadEvent event) {
World world = event.getWorld();
Integer lockedTime = getLockedTimes().get(world.getName());
if (lockedTime != null) {
world.setTime(lockedTime);
lock(world);
CommandBook.logger().info("Time locked to '"
+ ChatUtil.getTimeString(lockedTime) + "' for world '"
+ world.getName() + "'");
}
}
@EventHandler
public void onWorldUnload(WorldUnloadEvent event) {
unlock(event.getWorld());
}
/**
* Get locked times.
*
* @return
*/
public Map<String, Integer> getLockedTimes() {
return lockedTimes;
}
public synchronized void unlock(World world) {
Integer id = tasks.get(world.getName());
if (id != null) {
CommandBook.server().getScheduler().cancelTask(id);
}
}
public synchronized void lock(World world) {
long time = world.getFullTime();
unlock(world);
int id = CommandBook.server().getScheduler().scheduleSyncRepeatingTask(
CommandBook.inst(), new TimeLocker(world, time), 20, config.timeLockDelay);
tasks.put(world.getName(), id);
}
/**
* Parse a time string.
*
* @param timeStr
* @return
* @throws CommandException
*/
@Deprecated
public static int matchTime(String timeStr) throws CommandException {
return InputUtil.TimeParser.matchMCWorldTime(timeStr);
}
public class Commands {
@Command(aliases = {"time"},
usage = "[world] <time|\"current\">", desc = "Get/change the world time",
flags = "ls", min = 0, max = 2)
public void time(CommandContext args, CommandSender sender) throws CommandException {
World world;
String timeStr;
boolean onlyLock = false;
// Easy way to get the time
if (args.argsLength() == 0) {
world = PlayerUtil.checkPlayer(sender).getWorld();
timeStr = "current";
// If no world was specified, get the world from the sender, but
// fail if the sender isn't player
} else if (args.argsLength() == 1) {
world = PlayerUtil.checkPlayer(sender).getWorld();
timeStr = args.getString(0);
} else { // A world was specified!
world = InputUtil.LocationParser.matchWorld(sender, args.getString(0));
timeStr = args.getString(1);
}
boolean broadcastChanges = CommandBook.inst().broadcastChanges;
if (broadcastChanges && args.hasFlag('s')) {
CommandBook.inst().checkPermission(sender, "commandbook.time.silent");
broadcastChanges = false;
}
// Let the player get the time
if (timeStr.equalsIgnoreCase("current")
|| timeStr.equalsIgnoreCase("cur")
|| timeStr.equalsIgnoreCase("now")) {
// We want to lock to the current time
if (!args.hasFlag('l')) {
CommandBook.inst().checkPermission(sender, "commandbook.time.check");
sender.sendMessage(ChatColor.YELLOW
+ "Time: " + ChatUtil.getTimeString(world.getTime()));
return;
}
onlyLock = true;
}
CommandBook.inst().checkPermission(sender, "commandbook.time");
if (!onlyLock) {
unlock(world);
world.setTime(InputUtil.TimeParser.matchMCWorldTime(timeStr));
}
String verb = "set";
// Locking
if (args.hasFlag('l')) {
CommandBook.inst().checkPermission(sender, "commandbook.time.lock");
lock(world);
verb = "locked";
}
if (broadcastChanges) {
CommandBook.server().broadcastMessage(ChatColor.YELLOW
+ ChatUtil.toColoredName(sender, ChatColor.YELLOW) + " " + verb + " the time of '"
+ world.getName() + "' to "
+ ChatUtil.getTimeString(world.getTime()) + ".");
} else {
sender.sendMessage(ChatColor.YELLOW + "Time " + verb + " to "
+ ChatUtil.getTimeString(world.getTime()) + ".");
}
}
@Command(aliases = {"playertime"},
usage = "[filter] <time|\"current\">", desc = "Get/change a player's time",
flags = "rsw", min = 0, max = 2)
public void playertime(CommandContext args, CommandSender sender) throws CommandException {
Iterable<Player> players = null;
String timeStr = "current";
boolean included = false;
boolean reset = args.hasFlag('r');
if (args.argsLength() < 2) {
if (args.argsLength() == 1) {
timeStr = args.getString(0);
if (reset) {
players = InputUtil.PlayerParser.matchPlayers(sender, timeStr);
}
}
if (players == null) {
players = Lists.newArrayList(PlayerUtil.checkPlayer(sender));
}
} else {
players = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0));
timeStr = args.getString(1);
}
for (Player player : players) {
if (player != sender ) {
CommandBook.inst().checkPermission(sender, "commandbook.time.player.other");
break;
} else {
CommandBook.inst().checkPermission(sender, "commandbook.time.player");
}
}
if (args.hasFlag('r')) {
for (Player player : players) {
player.resetPlayerTime();
if (!args.hasFlag('s')) {
player.sendMessage(ChatColor.YELLOW + "Your time was reset to world time");
}
if (sender instanceof Player && sender.equals(player)) {
included = true;
}
}
if (!included) {
sender.sendMessage(ChatColor.YELLOW + "Player times reset");
}
return;
}
if (timeStr.equalsIgnoreCase("current")
|| timeStr.equalsIgnoreCase("cur")
|| timeStr.equalsIgnoreCase("now")) {
CommandBook.inst().checkPermission(sender, "commandbook.time.player.check");
sender.sendMessage(ChatColor.YELLOW
+ "Player Time: " + ChatUtil.getTimeString(InputUtil.PlayerParser.matchSinglePlayer(sender,
args.getString(0, PlayerUtil.checkPlayer(sender).getName())).getPlayerTime()));
return;
}
int time = InputUtil.TimeParser.matchMCWorldTime(timeStr);
for (Player player : players) {
if (player.equals(sender)) {
included = true;
}
player.setPlayerTime(args.hasFlag('w') ? Integer.parseInt(timeStr) : time, args.hasFlag('w'));
player.sendMessage(ChatColor.YELLOW + "Your time set to " + ChatUtil.getTimeString(player.getPlayerTime()));
}
if (!included) {
sender.sendMessage(ChatColor.YELLOW + "Player times set to " + ChatUtil.getTimeString(time));
}
}
}
}