/*** * 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", "")); }
/*** * 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); } }
/*** * 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(); }