/* * ReActions, Minecraft bukkit plugin * (c)2012-2017, fromgate, fromgate@gmail.com * http://dev.bukkit.org/server-mods/reactions/ * * * This file is part of ReActions. * * ReActions 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. * * ReActions 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 ReActions. If not, see <http://www.gnorg/licenses/>. * */ package me.fromgate.reactions.timer; import me.fromgate.reactions.ReActions; import me.fromgate.reactions.event.EventManager; import me.fromgate.reactions.util.Param; import me.fromgate.reactions.util.message.M; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.scheduler.BukkitTask; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; public class Timers { /* Command example: /react add timer <name> activator:<exec> time:<HH:MM,HH:MM|0_0/5_*_*_*_?> [player:<player>] [world:<world>] Example Cron Expressions CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes "0 0/5 * * * ?" CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.). "10 0/5 * * * ?" CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday. "0 30 10-13 ? * WED,FRI" CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month. Note that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30 "0 0/30 8-9 5,20 * ?" Note that some scheduling requirements are too complicated to express with a single trigger - such as "every 5 minutes between 9:00 am and 10:00 am, and every 20 minutes between 1:00 pm and 10:00 pm". The solution in this scenario is to simply create two triggers, and register both of them to run the same job. */ /* * TODO * нужно будет добавить поддержку временных поясов * */ private static BukkitTask ingameTimer = null; private static String currentIngameTime; private static BukkitTask serverTimer = null; private static Map<String, Timer> timers; private static Set<String> timersIngame; private static final int LINES_PER_PAGE_15 = 15; public static boolean addTimer(String name, Param params) { return addTimer(null, name, params, false); } public static void listTimers(CommandSender sender, int pageNum) { List<String> timerList = new ArrayList<>(); Map<String, Timer> timers = getIngameTimers(); for (String id : timers.keySet()) { Timer timer = timers.get(id); timerList.add((timer.isPaused() ? "&c" : "&2") + id + " &a" + timer.toString()); } timers = getServerTimers(); for (String id : timers.keySet()) { Timer timer = timers.get(id); timerList.add((timer.isPaused() ? "&c" : "&2") + id + " &a" + timer.toString()); } M.printPage(sender, timerList, M.MSG_TIMERLIST, pageNum, LINES_PER_PAGE_15, true); } public static boolean removeTimer(CommandSender sender, String name) { if (name.isEmpty()) { M.MSG_TIMERNEEDNAME.print(sender); return false; } if (!timers.containsKey(name)) { M.MSG_TIMERUNKNOWNNAME.print(sender, name); return false; } timers.remove(name); save(); return M.MSG_TIMERREMOVED.print(sender, name); } public static boolean addTimer(CommandSender sender, String name, Param params, boolean save) { if (name.isEmpty()) return false; if (timers.containsKey(name)) { M.MSG_TIMEREXIST.print(sender, name); return false; } if (params.isEmpty()) { M.MSG_TIMERNEEDPARAMS.print(sender); return false; } if (params.getParam("activator", "").isEmpty()) { M.MSG_TIMERNEEDACTIVATOR.print(sender); return false; } if (!params.isParamsExists("timer-type")) { M.MSG_TIMERNEEDTYPE.print(sender); return false; } if (!params.isParamsExists("time")) { M.MSG_TIMERNEEDTIME.print(sender); return false; } Timer timer = new Timer(params); timers.put(name, timer); updateIngameTimers(); if (save) save(); return M.MSG_TIMERADDED.print(sender, name); } public static Map<String, Timer> getIngameTimers() { Map<String, Timer> ingameTimers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); for (String key : timers.keySet()) { Timer timer = timers.get(key); if (timer.isIngameTimer()) ingameTimers.put(key, timer); } return ingameTimers; } public static Map<String, Timer> getServerTimers() { Map<String, Timer> serverTimers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); for (String key : timers.keySet()) { Timer timer = timers.get(key); if (!timer.isIngameTimer()) serverTimers.put(key, timer); } return serverTimers; } public static void updateIngameTimers() { timersIngame.clear(); Map<String, Timer> ingame = getIngameTimers(); for (String key : ingame.keySet()) { Timer timer = ingame.get(key); timersIngame.addAll(timer.getIngameTimes()); } } public static void init() { currentIngameTime = ""; timersIngame = new HashSet<>(); timers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); load(); initIngameTimer(); initServerTimer(); } public static void initIngameTimer() { if (ingameTimer != null) return; ingameTimer = Bukkit.getScheduler().runTaskTimerAsynchronously(ReActions.instance, new Runnable() { @Override public void run() { String currentTime = Time.currentIngameTime(); if (currentIngameTime.equalsIgnoreCase(currentTime)) return; currentIngameTime = currentTime; if (!timersIngame.contains(currentIngameTime)) return; Map<String, Timer> timers = getIngameTimers(); for (String key : timers.keySet()) { Timer timer = timers.get(key); if (timer.isTimeToRun()) { EventManager.raiseExecEvent(null, timer.getParams()); } } } }, 1, 4); //1 По идее так не упустим, хотя.... ;) } public static void initServerTimer() { if (serverTimer != null) return; serverTimer = Bukkit.getScheduler().runTaskTimerAsynchronously(ReActions.instance, new Runnable() { @Override public void run() { for (Timer timer : getServerTimers().values()) { if (timer.isTimeToRun()) { EventManager.raiseExecEvent(null, timer.getParams()); } } } }, 1, 20); } public static String getCurrentIngameTime() { return currentIngameTime; } public static void onDisable() { ingameTimer.cancel(); serverTimer.cancel(); } public static void load() { timers.clear(); YamlConfiguration cfg = new YamlConfiguration(); File f = new File(ReActions.instance.getDataFolder() + File.separator + "timers.yml"); if (!f.exists()) return; try { cfg.load(f); } catch (Exception e) { M.logMessage("Failed to save timers.yml file"); return; } for (String timerType : cfg.getKeys(false)) { if (!(timerType.equalsIgnoreCase("INGAME") || timerType.equalsIgnoreCase("SERVER"))) continue; ConfigurationSection cs = cfg.getConfigurationSection(timerType); if (cs == null) continue; for (String timerId : cs.getKeys(false)) { ConfigurationSection csParams = cs.getConfigurationSection(timerId); if (csParams == null) continue; Param params = new Param(); params.set("timer-type", timerType); for (String param : csParams.getKeys(true)) { if (!csParams.isString(param)) continue; params.set(param, csParams.getString(param)); } addTimer(timerId, params); } } } public static void save() { YamlConfiguration cfg = new YamlConfiguration(); File f = new File(ReActions.instance.getDataFolder() + File.separator + "timers.yml"); if (f.exists()) f.delete(); for (String name : timers.keySet()) { Timer timer = timers.get(name); Param params = timer.getParams(); if (params.isEmpty()) continue; String timerType = timer.isIngameTimer() ? "INGAME" : "SERVER"; String root = timerType + "." + name + "."; for (String key : params.keySet()) { if (key.equalsIgnoreCase("timer-type")) continue; if (key.equalsIgnoreCase("param-line")) continue; cfg.set(root + key, key.equalsIgnoreCase("time") ? params.getParam(key).replace("_", " ") : params.getParam(key)); } } try { cfg.save(f); } catch (IOException e) { M.logMessage("Failed to save timers.yml file"); } } public static boolean isTimerExists(String timerName) { return timers.containsKey(timerName); } public static boolean setPause(String timerName, boolean pause) { if (timers.isEmpty()) return false; if (!(timerName.equalsIgnoreCase("all") || isTimerExists(timerName))) return false; if (timerName.equalsIgnoreCase("all")) { for (Timer timer : timers.values()) timer.setPause(pause); } else { Timer timer = timers.get(timerName); timer.setPause(pause); } return true; } public static boolean isTimerWorking(String timerName) { if (!isTimerExists(timerName)) return false; return (!timers.get(timerName).isPaused()); } }