/*** * OnDisable */ @Override public void onDisable() { // kicks all players when the plugin is disabled (server is shutdown) for (Player player : Bukkit.getOnlinePlayers()){ player.kickPlayer(ChatColor.RED + _("shutdownKickMessage", player.getName())); } // if we don't have per-player language loaded from DB, do not try to load it now :-) avoidDB = true; // execute everything that should be executed on disable if (onDisableFunctions.size() > 0) { Class<?>[] proto = new Class[] {this.getClass()}; Object[] params = new Object[] {this}; for (String s : onDisableFunctions) { try { String[] ss = s.split("#####"); Class<?> c = Class.forName(ss[0]); Method method = c.getDeclaredMethod(ss[1], proto); method.invoke(null, params); } catch (Throwable e) { LogHelper.logSevere("[CommandsEX] " + _("errorFunctionOnDisableExecute", "") + s); LogHelper.logDebug("Message: " + e.getMessage() + ", cause: " + e.getCause()); } } } // close all database connections LogHelper.logInfo("[" + this.getDescription().getName() + "] " + _("disableMsg", "")); }
public void stopTimer(){ stopTime = System.currentTimeMillis(); finalTime = stopTime - startTime; if (getConf().getBoolean("startupTimer")){ LogHelper.logInfo("[CommandsEx] " + _("startupTime", "") + finalTime + "ms"); } }
/*** * When a player leaves the server, their join timestamp and playtime is removed to free up memory. * Playtime will get stored into database if the time since his joining is more than 45 seconds * to prevent database overloading when player tries to spam logins/logouts. * @param e */ @EventHandler(priority = EventPriority.NORMAL) public void pQuit(PlayerQuitEvent e) { String pName = e.getPlayer().getName(); Integer stamp = Utils.getUnixTimestamp(0L); // schedule player's IP removal CommandsEX.plugin.getServer().getScheduler().scheduleSyncDelayedTask(CommandsEX.plugin, new DelayedIpRemoval(pName), (20 * getConf().getInt("maxIPholdTime"))); // save player's playtime if (sqlEnabled && joinTimes.containsKey(pName)) { Integer played = (stamp - joinTimes.get(pName)); if (played >= minTimeToSavePlayTime) { // player was online for more than minTimeToSavePlayTime seconds, count this visit if (playTimes.containsKey(pName) && (playTimes.get(pName) > -1)) { // update playtime directly if we have previous time loaded playTimes.put(pName, (playTimes.get(pName) + played)); } else { // get total playtime from database, since we don't have it loaded yet try { // first, reset the time, so we don't add to -1 later Integer pTime = 0; ResultSet res = SQLManager.query_res("SELECT seconds_played FROM " + SQLManager.prefix + "playtime WHERE player_name = ?", pName); while (res.next()) { pTime = res.getInt("seconds_played"); } res.close(); playTimes.put(pName, (pTime + played)); } catch (Throwable ex) { // something went wrong... LogHelper.logSevere("[CommandsEX] " + _("dbTotalPlayTimeGetError", "")); LogHelper.logDebug("Message: " + ex.getMessage() + ", cause: " + ex.getCause()); } } // update DB with new value played = playTimes.get(pName); SQLManager.query("INSERT "+ (SQLManager.sqlType.equals("mysql") ? "" : "OR REPLACE ") +"INTO " + SQLManager.prefix + "playtime VALUES (?, ?)"+ (SQLManager.sqlType.equals("mysql") ? " ON DUPLICATE KEY UPDATE seconds_played = VALUES(seconds_played)" : ""), pName, played); } joinTimes.remove(pName); playTimes.remove(pName); } }
/** * * Extinguish - Allows a player (or console) to extinguish themself or another player. * * @author iKeirNez * @param sender * @param args * @return */ public static Boolean run(CommandSender sender, String alias, String[] args) { if (sender instanceof Player) { Player player = (Player) sender; if (Utils.checkCommandSpam(player, "cex_extinguish")) { return true; } } if (args.length == 0) { if (sender instanceof Player) { Player player = (Player) sender; player.setFireTicks(0); LogHelper.showInfo("extExtinguished", player, ChatColor.GREEN); } else { LogHelper.showInfo("playerNameMissing", sender, ChatColor.RED); } } else if (args.length == 1) { Player toExt = Bukkit.getPlayer(args[0]); if (toExt != null) { // Prevents the player from recieving 2 messages if they do /ext <their-player-name> if (toExt != sender) { if ((!(sender instanceof Player)) || ((Player) sender).hasPermission("cex.extinguish.others")) { toExt.setFireTicks(0); LogHelper.showInfo( "extExtinguishedBySomeoneElse#####[ " + sender.getName(), toExt, ChatColor.GREEN); LogHelper.showInfo( "extExtinguishedSomeoneElse#####[ " + toExt.getName(), sender, ChatColor.GREEN); } else { LogHelper.showInfo("extOtherNoPerm", sender, ChatColor.RED); } } else { toExt.setFireTicks(0); LogHelper.showInfo("extExtinguished", sender, ChatColor.GREEN); } } else { LogHelper.showInfo("invalidPlayer", sender, ChatColor.RED); } } else { LogHelper.showInfo("incorrectUsage", sender, ChatColor.RED); } return true; }
/*** * The main function which replaces chat with matched replacements. * @param e * @return */ @EventHandler(priority = EventPriority.LOWEST) public void replaceChat(PlayerChatEvent e) { if (e.isCancelled()) return; try { ScriptEnvironment env = new ScriptEnvironment(); { env.setCommandSender(e.getPlayer()); env.setServer(e.getPlayer().getServer()); } ArrayList<ReplacementPair> preparedEffects = new ArrayList<ReplacementPair>(); //holds all effects until all replacements done for (ReplacementPair rp : pairs) { StringBuffer sb = new StringBuffer(); Matcher m = rp.getRegex().matcher(e.getMessage()); if (!m.find()) continue; env.setMatcher(m); if (rp.playerWillVanish()) { //the player will vanish as a result of this, special handling int cutlen = CommandsEX.getConf().getInt("replacements.cutoff.length", 1); String cuttext = CommandsEX.getConf().getString("replacements.cutoff.indicator", "--*"); String rep = m.group().substring(0, cutlen).concat(cuttext); m.appendReplacement(sb, rep); e.setMessage(sb.toString()); //e.setCancelled(true); //e.getPlayer().chat(sb.toString()); //chat first rp.executeEffects(env); //then execute the replacement return; } //loop through with find/replace do { //use do while, due to the find() invocation above // test if it is all upper, and replace with all upper (if we have this set up in the regex itself - in config file) if (rp.getSameOutputCase() && allUpper && m.group().toUpperCase().equals(m.group())) { m.appendReplacement(sb, rp.executeString(env).toUpperCase()); } else { m.appendReplacement(sb, rp.executeString(env)); } } while (m.find()); m.appendTail(sb); if (!preparedEffects.contains(rp)) { preparedEffects.add(rp); } e.setMessage(sb.toString()); } //after all replacements are in: execute the effects if (!preparedEffects.isEmpty()) { //e.setCancelled(true); //e.getPlayer().chat(sb.toString()); //chat first env.setMatcher(null); for (ReplacementPair rp : preparedEffects){ rp.executeEffects(env); } } } catch (Exception ex){ LogHelper.logSevere("[CommandsEX] " + _("cmdOrChatreplacementFailed", "")); LogHelper.logDebug("Message: " + ex.getMessage() + ", cause: " + ex.getCause()); } }
/*** * OnEnable */ @Override public void onEnable() { startTimer(); // save default config if not saved yet getConfig().options().copyDefaults(true); saveConfig(); // check for Vault plugin presence try { new Vault(); vaultPresent = true; } catch (Throwable e) {} // set up commands listener cListener = new Commands(this); // initialize translations Language.init(this); // get description file and display initial startup OK info pdfFile = this.getDescription(); LogHelper.logInfo("[" + pdfFile.getName() + "] " + _("startupMessage", "") + " " + Language.defaultLocale); LogHelper.logInfo("[" + pdfFile.getName() + "] " + _("version", "") + " " + pdfFile.getVersion() + " " + _("enableMsg", "")); // initialize database, if we have it included in our build Class<?>[] proto = new Class[] {this.getClass()}; Object[] params = new Object[] {this}; if (getConf().getBoolean("enableDatabase")) { try { Class<?> c = Class.forName("com.github.zathrus_writer.commandsex.SQLManager"); Method method = c.getDeclaredMethod("init", proto); method.invoke(null, params); } catch (ClassNotFoundException e) { // this is OK, since we won't neccessarily have this class in each build } catch (Throwable e) { LogHelper.logSevere(_("dbError", "")); LogHelper.logDebug("Message: " + e.getMessage() + ", cause: " + e.getCause()); } } // enable existing classes that are listening to events - determine names from permissions // ... also call init() function for each helper class that requires initialization (has Init prefix in permissions) List<Permission> perms = CommandsEX.pdfFile.getPermissions(); for(int i = 0; i <= perms.size() - 1; i++) { // call initialization function for each of the event handling functions String pName = perms.get(i).getName(); if (pName.startsWith("Listener")) { String[] s = pName.split("\\."); if (s.length == 0) continue; try { Class.forName("com.github.zathrus_writer.commandsex.handlers.Handler_" + s[1]).newInstance(); } catch (ClassNotFoundException e) { // this is OK, since we won't neccessarily have this class in each build } catch (Throwable e) { LogHelper.logSevere(_("loadTimeError", "")); LogHelper.logDebug("Message: " + e.getMessage() + ", cause: " + e.getCause()); } } else if (pName.startsWith("Init")) { String[] s = pName.split("\\."); if (s.length == 0) continue; try { Class<?> c = Class.forName("com.github.zathrus_writer.commandsex.helpers." + s[1]); Method method = c.getDeclaredMethod("init", proto); method.invoke(null, params); } catch (ClassNotFoundException e) { // this is OK, since we won't neccessarily have this class in each build } catch (Throwable e) { LogHelper.logSevere(_("loadTimeError", "")); LogHelper.logDebug("Message: " + e.getMessage() + ", cause: " + e.getCause()); } } } // setup a recurring task that will periodically save players' play times into DB if (sqlEnabled) { getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() { @Override public void run() { // flush play times only for players that have their playtime loaded initially Integer stamp = Utils.getUnixTimestamp(0L); Iterator<Entry<String, Integer>> it = CommandsEX.playTimes.entrySet().iterator(); List<Object> insertParts = new ArrayList<Object>(); List<Object> insertValues = new ArrayList<Object>(); while (it.hasNext()) { Map.Entry<String, Integer> pairs = (Map.Entry<String, Integer>)it.next(); // only update data for players that don't have -1 set as their playTime if (pairs.getValue() <= -1) continue; String pName = pairs.getKey(); // update play time and join time Integer played = (pairs.getValue() + (stamp - CommandsEX.joinTimes.get(pName))); CommandsEX.playTimes.put(pName, played); CommandsEX.joinTimes.put(pName, Utils.getUnixTimestamp(0L)); // prepare DB query parts insertParts.add("SELECT ? AS 'player_name', ? AS 'seconds_played'"); insertValues.add(pName); insertValues.add(played); //it.remove(); // avoids a ConcurrentModificationException - not needed in our case and will clear out HashMap! } if (insertParts.size() > 0) { // update the database SQLManager.query("INSERT "+ (SQLManager.sqlType.equals("mysql") ? "" : "OR REPLACE ") +"INTO " + SQLManager.prefix + "playtime "+ Utils.implode(insertParts, " UNION ") + (SQLManager.sqlType.equals("mysql") ? " ON DUPLICATE KEY UPDATE seconds_played = VALUES(seconds_played)" : ""), insertValues); } } }, (20 * playTimesFlushTime), (20 * playTimesFlushTime)); // tell Bukkit we have some event handling to do in this class :-) this.getServer().getPluginManager().registerEvents(this, this); } try { Metrics metrics = new Metrics(plugin); metrics.start(); } catch (IOException e) { } stopTimer(); }
/*** * When a player joins the server, their join timestamp is saved, helping us to determine * how long he's been online. Also, a new delayed task will be created that will load up player's * full playtime from database, should the player stay on the server for more than minTimeFromLogout seconds. * * Additionally, when a player joins the server, their IP is stored internally to allow for IP-banning when * the player leaves as soon as they burst-grief. * @param e */ @EventHandler(priority = EventPriority.NORMAL) public void pJoin(PlayerJoinEvent e) { String pName = e.getPlayer().getName(); playerIPs.put(pName.toLowerCase(), e.getPlayer().getAddress().getAddress().getHostAddress()); // check if player is not jailed try { if (Jails.jailedPlayers.containsKey(pName)) { LogHelper.showInfo("jailsStillJailed", e.getPlayer()); } } catch (Throwable ex) {} if (sqlEnabled) { // add -1 to playtimes, so our Runnable function will know to look the player up after the delay has passed playTimes.put(pName, -1); joinTimes.put(pName, Utils.getUnixTimestamp(0L)); // cancel out any previously delayed task created by this user if (this.playTimeLoadTasks.containsKey(pName)) { this.getServer().getScheduler().cancelTask(this.playTimeLoadTasks.get(pName)); } // add new delayed task to load user's playtime from DB this.playTimeLoadTasks.put(pName, this.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() { @Override public void run() { // load playtimes for all players with time set to -1 and valid time on the server (i.e. +(minTimeFromLogout - 5) seconds) // ... and -5 seconds to allow for server lag and similar things to happen :-) Iterator<Entry<String, Integer>> it = CommandsEX.playTimes.entrySet().iterator(); List<String> playerNames = new ArrayList<String>(); Integer stamp = Utils.getUnixTimestamp(0L); while (it.hasNext()) { Map.Entry<String, Integer> pairs = (Map.Entry<String, Integer>)it.next(); // only check players with -1 as playtime if (pairs.getValue() > -1) continue; // check if the player's last logout time was not within last minTimeFromLogout seconds, in which case we don't bother // checking up on him and his playtime will be loaded as needed on Quit event String pName = (String)pairs.getKey(); OfflinePlayer o = CommandsEX.plugin.getServer().getOfflinePlayer(pName); if ((o != null) && (o.getLastPlayed() > 0)) { // convert miliseconds of player last visit time to seconds Integer lastPlay = Utils.getUnixTimestamp(o.getLastPlayed()); // check if we should be adding the player, based on last quitting time if ((stamp - lastPlay) >= (CommandsEX.minTimeFromLogout - 5)) { playerNames.add(pName); } } else { // this is a new player, set his playtime to 0 CommandsEX.playTimes.put(pName, 0); } //it.remove(); // avoids a ConcurrentModificationException - not needed in our case and will clear out HashMap! } // load playtimes from DB Integer pSize = playerNames.size(); if (pSize > 0) { try { String[] qMarks = new String[pSize]; Arrays.fill(qMarks, "?"); ResultSet res = SQLManager.query_res("SELECT * FROM " + SQLManager.prefix + "playtime WHERE player_name IN ("+ Utils.implode(qMarks, ", ") +")", playerNames); while (res.next()) { CommandsEX.playTimes.put(res.getString("player_name"), res.getInt("seconds_played")); } res.close(); } catch (Throwable e) { // unable to load players' playtimes, show up on console LogHelper.logSevere("[CommandsEX] " + _("dbTotalPlayTimeGetError", "")); LogHelper.logDebug("Message: " + e.getMessage() + ", cause: " + e.getCause()); return; } } } }, (20 * minTimeFromLogout))); } }
/** * * Give - Gives a player an item Could be improved in the future by adding enchantment support * * @param sender * @param args * @return */ public static boolean run(CommandSender sender, String alias, String[] args) { if (sender instanceof Player) { Player player = (Player) sender; if (Utils.checkCommandSpam(player, "cex_give")) { return true; } } if (sender instanceof Player) { Player player = (Player) sender; if (Utils.checkCommandSpam(player, "cex_give")) { return true; } } if (args.length < 2 || args.length > 3) { System.out.println("Incorrect args"); Commands.showCommandHelpAndUsage(sender, "cex_give", alias); } else { String item; short damage = 0; int amount = 64; Player target = Bukkit.getPlayer(args[0]); if (target == null) { LogHelper.showInfo("invalidPlayer", sender, ChatColor.RED); return true; } if (args[1].contains(":")) { String[] data = args[1].split(":"); item = data[0]; try { damage = Short.valueOf(args[1].split(":")[1]); } catch (Exception e) { LogHelper.showInfo("itemIncorrectDamageValue", sender, ChatColor.RED); Commands.showCommandHelpAndUsage(sender, "cex_give", alias); return true; } } else { item = args[1]; } if (args.length == 3) { try { amount = Integer.valueOf(args[2]); } catch (Exception e) { LogHelper.showInfo("itemIncorrectDamageValue", sender, ChatColor.RED); Commands.showCommandHelpAndUsage(sender, "cex_give", alias); return true; } } if (Utils.closestMatches(item).size() > 0) { List<Material> matches = Utils.closestMatches(item); giveItem(sender, target, matches.get(0), amount, damage); } else { LogHelper.showInfo("itemNotFound", sender, ChatColor.RED); } } return true; }