diff --git a/src/main/java/ch/njol/skript/ScriptLoader.java b/src/main/java/ch/njol/skript/ScriptLoader.java index 7cf3bdd3321..5dd981d82e6 100644 --- a/src/main/java/ch/njol/skript/ScriptLoader.java +++ b/src/main/java/ch/njol/skript/ScriptLoader.java @@ -736,7 +736,7 @@ private static ScriptInfo loadScript(@Nullable Config config) { event = replaceOptions(event); - NonNullPair, SkriptEvent> parsedEvent = SkriptParser.parseEvent(event, "can't understand this event: '" + node.getKey() + "'"); + NonNullPair, SkriptEvent> parsedEvent = SkriptParser.parseEvent(event, "Can't understand this event: '" + node.getKey() + "'"); if (parsedEvent == null || !parsedEvent.getSecond().shouldLoadEvent()) continue; @@ -1160,7 +1160,7 @@ static Trigger loadTrigger(SectionNode node) { event = "" + event.substring("on ".length()); NonNullPair, SkriptEvent> parsedEvent = - SkriptParser.parseEvent(event, "can't understand this event: '" + node.getKey() + "'"); + SkriptParser.parseEvent(event, "Can't understand this event: '" + node.getKey() + "'"); if (parsedEvent == null) { assert false; return null; diff --git a/src/main/java/ch/njol/skript/SkriptCommand.java b/src/main/java/ch/njol/skript/SkriptCommand.java index d161731da8f..c063a448580 100644 --- a/src/main/java/ch/njol/skript/SkriptCommand.java +++ b/src/main/java/ch/njol/skript/SkriptCommand.java @@ -26,6 +26,8 @@ import java.util.List; import java.util.stream.Collectors; +import ch.njol.skript.log.TimingLogHandler; +import ch.njol.util.OpenCloseable; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -96,12 +98,14 @@ private static void reloading(CommandSender sender, String what, Object... args) private static final ArgsMessage m_reloaded = new ArgsMessage(CONFIG_NODE + ".reload.reloaded"); private static final ArgsMessage m_reload_error = new ArgsMessage(CONFIG_NODE + ".reload.error"); - private static void reloaded(CommandSender sender, RedirectingLogHandler r, String what, Object... args) { + private static void reloaded(CommandSender sender, RedirectingLogHandler r, TimingLogHandler timingLogHandler, String what, Object... args) { what = args.length == 0 ? Language.get(CONFIG_NODE + ".reload." + what) : PluralizingArgsMessage.format(Language.format(CONFIG_NODE + ".reload." + what, args)); + String timeTaken = String.valueOf(timingLogHandler.getTimeTaken()); + if (r.numErrors() == 0) - Skript.info(sender, StringUtils.fixCapitalization(PluralizingArgsMessage.format(m_reloaded.toString(what)))); + Skript.info(sender, StringUtils.fixCapitalization(PluralizingArgsMessage.format(m_reloaded.toString(what, timeTaken)))); else - Skript.error(sender, StringUtils.fixCapitalization(PluralizingArgsMessage.format(m_reload_error.toString(what, r.numErrors())))); + Skript.error(sender, StringUtils.fixCapitalization(PluralizingArgsMessage.format(m_reload_error.toString(what, r.numErrors(), timeTaken)))); } private static void info(CommandSender sender, String what, Object... args) { @@ -121,7 +125,8 @@ public boolean onCommand(@Nullable CommandSender sender, @Nullable Command comma throw new IllegalArgumentException(); if (!skriptCommandHelp.test(sender, args)) return true; - try (RedirectingLogHandler logHandler = new RedirectingLogHandler(sender, "").start()) { + try (RedirectingLogHandler logHandler = new RedirectingLogHandler(sender, "").start(); + TimingLogHandler timingLogHandler = new TimingLogHandler().start()) { if (args[0].equalsIgnoreCase("reload")) { if (args[1].equalsIgnoreCase("all")) { reloading(sender, "config, aliases and scripts"); @@ -132,27 +137,27 @@ public boolean onCommand(@Nullable CommandSender sender, @Nullable Command comma if (!ScriptLoader.isAsync()) ScriptLoader.disableScripts(); - ScriptLoader.loadScripts(logHandler) + ScriptLoader.loadScripts(OpenCloseable.combine(logHandler, timingLogHandler)) .thenAccept(unused -> - reloaded(sender, logHandler, "config, aliases and scripts")); + reloaded(sender, logHandler, timingLogHandler, "config, aliases and scripts")); } else if (args[1].equalsIgnoreCase("scripts")) { reloading(sender, "scripts"); if (!ScriptLoader.isAsync()) ScriptLoader.disableScripts(); - ScriptLoader.loadScripts(logHandler) + ScriptLoader.loadScripts(OpenCloseable.combine(logHandler, timingLogHandler)) .thenAccept(unused -> - reloaded(sender, logHandler, "scripts")); + reloaded(sender, logHandler, timingLogHandler, "scripts")); } else if (args[1].equalsIgnoreCase("config")) { reloading(sender, "main config"); SkriptConfig.load(); - reloaded(sender, logHandler, "main config"); + reloaded(sender, logHandler, timingLogHandler, "main config"); } else if (args[1].equalsIgnoreCase("aliases")) { reloading(sender, "aliases"); Aliases.clear(); Aliases.load(); - reloaded(sender, logHandler, "aliases"); + reloaded(sender, logHandler, timingLogHandler, "aliases"); } else { File f = getScriptFromArgs(sender, args, 1); if (f == null) @@ -163,18 +168,18 @@ public boolean onCommand(@Nullable CommandSender sender, @Nullable Command comma return true; } reloading(sender, "script", f.getName()); - ScriptLoader.reloadScript(f, logHandler) + ScriptLoader.reloadScript(f, OpenCloseable.combine(logHandler, timingLogHandler)) .thenAccept(scriptInfo -> - reloaded(sender, logHandler, "script", f.getName())); + reloaded(sender, logHandler, timingLogHandler, "script", f.getName())); } else { reloading(sender, "scripts in folder", f.getName()); - ScriptLoader.reloadScripts(f, logHandler) + ScriptLoader.reloadScripts(f, OpenCloseable.combine(logHandler, timingLogHandler)) .thenAccept(scriptInfo -> { int enabled = scriptInfo.files; if (enabled == 0) info(sender, "reload.empty folder", f.getName()); else - reloaded(sender, logHandler, "x scripts in folder", f.getName(), enabled); + reloaded(sender, logHandler, timingLogHandler, "x scripts in folder", f.getName(), enabled); }); } } diff --git a/src/main/java/ch/njol/skript/command/ScriptCommand.java b/src/main/java/ch/njol/skript/command/ScriptCommand.java index f52b418a69f..007cbec8871 100644 --- a/src/main/java/ch/njol/skript/command/ScriptCommand.java +++ b/src/main/java/ch/njol/skript/command/ScriptCommand.java @@ -268,7 +268,7 @@ boolean execute2(final ScriptCommandEvent event, final CommandSender sender, fin if (!ok) { final LogEntry e = log.getError(); if (e != null) - sender.sendMessage(ChatColor.DARK_RED + e.getMessage()); + sender.sendMessage(ChatColor.DARK_RED + e.toString()); sender.sendMessage(usage); log.clear(); return false; diff --git a/src/main/java/ch/njol/skript/expressions/ExprParse.java b/src/main/java/ch/njol/skript/expressions/ExprParse.java index 5a8f010add9..14df7ceaf02 100644 --- a/src/main/java/ch/njol/skript/expressions/ExprParse.java +++ b/src/main/java/ch/njol/skript/expressions/ExprParse.java @@ -182,7 +182,7 @@ protected Object[] get(Event e) { } LogEntry err = h.getError(); if (err != null) { - lastError = err.getMessage(); + lastError = err.toString(); } else { if (c != null) { lastError = t + " could not be parsed as " + c.getName().withIndefiniteArticle(); diff --git a/src/main/java/ch/njol/skript/localization/Message.java b/src/main/java/ch/njol/skript/localization/Message.java index 7705838352d..3cce636f90b 100644 --- a/src/main/java/ch/njol/skript/localization/Message.java +++ b/src/main/java/ch/njol/skript/localization/Message.java @@ -78,7 +78,7 @@ public String toString() { * @return This message's value or null if it doesn't exist. */ @Nullable - protected final String getValue() { + public final String getValue() { validate(); return value; } diff --git a/src/main/java/ch/njol/skript/log/LogEntry.java b/src/main/java/ch/njol/skript/log/LogEntry.java index 9d358800c9b..aec362311de 100644 --- a/src/main/java/ch/njol/skript/log/LogEntry.java +++ b/src/main/java/ch/njol/skript/log/LogEntry.java @@ -20,6 +20,8 @@ import java.util.logging.Level; +import ch.njol.skript.localization.ArgsMessage; +import ch.njol.skript.util.Utils; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; @@ -42,7 +44,15 @@ public class LogEntry { @Nullable private final String from; private final boolean tracked; - + + private static final String CONFIG_NODE = "skript command.reload"; + private static final ArgsMessage WARNING_LINE_INFO = new ArgsMessage(CONFIG_NODE + ".warning line info"); + private static final ArgsMessage ERROR_LINE_INFO = new ArgsMessage(CONFIG_NODE + ".error line info"); + private static final ArgsMessage WARNING_DETAILS = new ArgsMessage(CONFIG_NODE + ".warning details"); + private static final ArgsMessage ERROR_DETAILS = new ArgsMessage(CONFIG_NODE + ".error details"); + private static final ArgsMessage OTHER_DETAILS = new ArgsMessage(CONFIG_NODE + ".other details"); + private static final ArgsMessage LINE_DETAILS = new ArgsMessage(CONFIG_NODE + ".line details"); + public LogEntry(Level level, String message) { this(level, ErrorQuality.SEMANTIC_ERROR.quality(), message, SkriptLogger.getNode()); } @@ -102,7 +112,7 @@ public int getQuality() { } public String getMessage() { - return toString(); + return message; } private boolean used = false; @@ -128,8 +138,41 @@ protected void finalize() { public String toString() { if (node == null || level.intValue() < Level.WARNING.intValue()) return message; + Config c = node.getConfig(); return message + from + " (" + c.getFileName() + ", line " + node.getLine() + ": " + node.save().trim() + "')"; } + + public String toFormattedString() { + if (node == null || level.intValue() < Level.WARNING.intValue()) + return message; + + Config c = node.getConfig(); + + ArgsMessage details; + ArgsMessage lineInfo = WARNING_LINE_INFO; + if (level.intValue() == Level.WARNING.intValue()) { // warnings + details = WARNING_DETAILS; + } else if (level.intValue() == Level.SEVERE.intValue()) { // errors + details = ERROR_DETAILS; + lineInfo = ERROR_LINE_INFO; + } else { // anything else + details = OTHER_DETAILS; + } + + // Replace configured messages chat styles without user variables + String lineInfoMsg = replaceNewline(Utils.replaceEnglishChatStyles(lineInfo.getValue() == null ? lineInfo.key : lineInfo.getValue())); + String detailsMsg = replaceNewline(Utils.replaceEnglishChatStyles(details.getValue() == null ? details.key : details.getValue())); + String lineDetailsMsg = replaceNewline(Utils.replaceEnglishChatStyles(LINE_DETAILS.getValue() == null ? LINE_DETAILS.key : LINE_DETAILS.getValue())); + + return + String.format(lineInfoMsg, String.valueOf(node.getLine()), c.getFileName()) + + String.format(detailsMsg, message.replaceAll("§", "&")) + from + + String.format(lineDetailsMsg, node.save().trim().replaceAll("§", "&")); + } + + private String replaceNewline(String s) { + return s.replaceAll("\\\\n", "\n"); + } } diff --git a/src/main/java/ch/njol/skript/log/RedirectingLogHandler.java b/src/main/java/ch/njol/skript/log/RedirectingLogHandler.java index 9b913f1bc1c..85b833ce535 100644 --- a/src/main/java/ch/njol/skript/log/RedirectingLogHandler.java +++ b/src/main/java/ch/njol/skript/log/RedirectingLogHandler.java @@ -18,16 +18,14 @@ */ package ch.njol.skript.log; -import java.util.logging.Level; - import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.eclipse.jdt.annotation.Nullable; +import java.util.logging.Level; + /** * Redirects the log to a {@link CommandSender}. - * - * @author Peter Güttinger */ public class RedirectingLogHandler extends LogHandler { @@ -46,9 +44,9 @@ public RedirectingLogHandler(CommandSender recipient, @Nullable String prefix) { @Override public LogResult log(LogEntry entry) { if (recipient != null) - recipient.sendMessage(prefix + entry); + recipient.sendMessage(prefix + entry.toFormattedString()); else - SkriptLogger.LOGGER.log(entry.getLevel(), prefix + entry); + SkriptLogger.LOGGER.log(entry.getLevel(), prefix + entry.toFormattedString()); if (entry.level == Level.SEVERE) numErrors++; return LogResult.DO_NOT_LOG; @@ -62,5 +60,5 @@ public RedirectingLogHandler start() { public int numErrors() { return numErrors; } - + } diff --git a/src/main/java/ch/njol/skript/log/RetainingLogHandler.java b/src/main/java/ch/njol/skript/log/RetainingLogHandler.java index 95efb4d7529..7ece5976c70 100644 --- a/src/main/java/ch/njol/skript/log/RetainingLogHandler.java +++ b/src/main/java/ch/njol/skript/log/RetainingLogHandler.java @@ -119,9 +119,9 @@ public final boolean printErrors(CommandSender recipient, @Nullable String def) for (LogEntry e : log) { if (e.getLevel().intValue() >= Level.SEVERE.intValue()) { if (console) - SkriptLogger.LOGGER.severe(e.getMessage()); + SkriptLogger.LOGGER.severe(e.toFormattedString()); else - recipient.sendMessage(e.getMessage()); + recipient.sendMessage(e.toFormattedString()); e.logged(); hasError = true; } else { diff --git a/src/main/java/ch/njol/skript/log/SkriptLogger.java b/src/main/java/ch/njol/skript/log/SkriptLogger.java index afd5c2b16f4..5603b0e8d0a 100644 --- a/src/main/java/ch/njol/skript/log/SkriptLogger.java +++ b/src/main/java/ch/njol/skript/log/SkriptLogger.java @@ -167,7 +167,7 @@ public static void log(@Nullable LogEntry entry) { if (entry == null) return; if (Skript.testing() && getNode() != null && getNode().debug()) - System.out.print("---> " + entry.level + "/" + ErrorQuality.get(entry.quality) + ": " + entry.getMessage() + " ::" + LogEntry.findCaller()); + System.out.print("---> " + entry.level + "/" + ErrorQuality.get(entry.quality) + ": " + entry + " ::" + LogEntry.findCaller()); for (LogHandler h : getHandlers()) { LogResult r = h.log(entry); switch (r) { @@ -181,7 +181,7 @@ public static void log(@Nullable LogEntry entry) { } } entry.logged(); - LOGGER.log(entry.getLevel(), "[Skript] " + entry.getMessage()); + LOGGER.log(entry.getLevel(), "[Skript] " + entry.toFormattedString()); } public static void logAll(Collection entries) { diff --git a/src/main/java/ch/njol/skript/log/TimingLogHandler.java b/src/main/java/ch/njol/skript/log/TimingLogHandler.java new file mode 100644 index 00000000000..a42c26d4b4b --- /dev/null +++ b/src/main/java/ch/njol/skript/log/TimingLogHandler.java @@ -0,0 +1,56 @@ +/** + * This file is part of Skript. + * + * Skript 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. + * + * Skript 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 Skript. If not, see . + * + * Copyright Peter Güttinger, SkriptLang team and contributors + */ + +/** + * A {@link LogHandler} that records the time since its creation. + */ +package ch.njol.skript.log; + +/** + * A log handler that records the time since its creation. + */ +public class TimingLogHandler extends LogHandler { + + private final long start = System.currentTimeMillis(); + + @Override + public LogResult log(LogEntry entry) { + return LogResult.LOG; + } + + @Override + public TimingLogHandler start() { + return SkriptLogger.startLogHandler(this); + } + + /** + * @return the time in milliseconds of when this log handler was created. + */ + public long getStart() { + return start; + } + + /** + * @return the time in milliseconds between now and this log handler's creation. + */ + public long getTimeTaken() { + return System.currentTimeMillis() - start; + } + +} diff --git a/src/main/resources/lang/english.lang b/src/main/resources/lang/english.lang index 886afbe96e9..f9ac66800c5 100644 --- a/src/main/resources/lang/english.lang +++ b/src/main/resources/lang/english.lang @@ -51,10 +51,16 @@ skript command: invalid script: Can't find the script '%s' in the scripts folder! invalid folder: Can't find the folder '%s' in the scripts folder! reload: - reloading: Reloading %s... - reloaded: Successfully reloaded %s. - error: Encountered %2$s error¦¦s¦ while reloading %1$s! + warning line info: Line %s: (%s)\n + error line info: Line %s: (%s)\n + reloading: Reloading %s... + reloaded: Successfully reloaded %s. (%2$sms) + error: Encountered %2$s error¦¦s¦ while reloading %1$s! (%3$sms) script disabled: %s is currently disabled. Use /skript enable %s to enable it. + warning details: %s\n + error details: %s\n + other details: %s\n + line details: Line: %s\n config, aliases and scripts: the config, aliases and all scripts scripts: all scripts diff --git a/src/main/resources/lang/german.lang b/src/main/resources/lang/german.lang index dc4b3b122b5..f9491f954bd 100644 --- a/src/main/resources/lang/german.lang +++ b/src/main/resources/lang/german.lang @@ -51,10 +51,16 @@ skript command: invalid script: Das Skript '%s' konnte nicht gefunden werden. invalid folder: Der Ordner '%s' konnte nicht gefunden werden. reload: - reloading: Lade %s neu... - reloaded: %s erfolgreich neu geladen. - error: %2$s Fehler ¦ist¦sind¦ beim Parsen aufgetreten! + warning line info: Linie %s: (%s)\n + error line info: Linie %s: (%s)\n + reloading: Lade %s neu... + reloaded: %s erfolgreich neu geladen. (%2$sms) + error: %2$s Fehler ¦ist¦sind¦ beim Parsen aufgetreten! (%2$sms) script disabled: %s ist derzeit deaktiviert. Verwende /skript enable %s um es zu aktivieren. + warning details: %s\n + error details: %s\n + other details: %s\n + line details: Linie: %s\n config, aliases and scripts: die Konfiguration, alle Itemnamen und alle Skripte scripts: alle Skripte diff --git a/src/main/resources/lang/korean.lang b/src/main/resources/lang/korean.lang index f708e3a94b7..1e606126238 100644 --- a/src/main/resources/lang/korean.lang +++ b/src/main/resources/lang/korean.lang @@ -51,10 +51,16 @@ skript command: invalid script: 스크립트 폴더에서 '%s' 스크립트를 찾을 수 없습니다! invalid folder: 스크립트 폴더에서 '%s' 폴더를 찾을 수 없습니다! reload: - reloading: %s을(를) 다시 로드하는 중입니다... - reloaded: %s을(를) 다시 로드했습니다. - error: %1$s을(를) 다시 로드하는 동안 %2$s개의 오류를 발견했습니다! + warning line info: 라인 %s: (%s)\n + error line info: 라인 %s: (%s)\n + reloading: %s을(를) 다시 로드하는 중입니다... + reloaded: %s을(를) 다시 로드했습니다. (%2$sms) + error: %1$s을(를) 다시 로드하는 동안 %2$s개의 오류를 발견했습니다! (%2$sms) script disabled: %s은 현재 비활성화되어 있습니다. /skript %s을 사용하여 활성화하십시오. + warning details: %s\n + error details: %s\n + other details: %s\n + line details: 라인: %s\n config, aliases and scripts: 구성(config), 별칭(aliases) 및 모든 스크립트 scripts: 모든 스크립트