--- ../src-base/minecraft/org/bukkit/command/defaults/TimingsCommand.java +++ ../src-work/minecraft/org/bukkit/command/defaults/TimingsCommand.java @@ -19,23 +19,97 @@ import com.google.common.collect.ImmutableList; +// Spigot start +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.util.logging.Level; + +import org.bukkit.command.RemoteConsoleCommandSender; +import org.bukkit.plugin.SimplePluginManager; +import org.spigotmc.CustomTimingsHandler; +// Spigot end + public class TimingsCommand extends BukkitCommand { - private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("merged", "reset", "separate"); + private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("report", "reset", "on", "off", "paste"); // Spigot + public static long timingStart = 0; // Spigot public TimingsCommand(String name) { super(name); - this.description = "Records timings for all plugin events"; - this.usageMessage = "/timings "; + this.description = "Manages Spigot Timings data to see performance of the server."; // Spigot + this.usageMessage = "/timings "; // Spigot this.setPermission("bukkit.command.timings"); } + // Spigot start - redesigned Timings Command + public void executeSpigotTimings(CommandSender sender, String[] args) { + if ( "on".equals( args[0] ) ) + { + ( (SimplePluginManager) Bukkit.getPluginManager() ).useTimings( true ); + CustomTimingsHandler.reload(); + sender.sendMessage( "Enabled Timings & Reset" ); + return; + } else if ( "off".equals( args[0] ) ) + { + ( (SimplePluginManager) Bukkit.getPluginManager() ).useTimings( false ); + sender.sendMessage( "Disabled Timings" ); + return; + } + + if ( !Bukkit.getPluginManager().useTimings() ) + { + sender.sendMessage( "Please enable timings by typing /timings on" ); + return; + } + + boolean paste = "paste".equals( args[0] ); + if ("reset".equals(args[0])) { + CustomTimingsHandler.reload(); + sender.sendMessage("Timings reset"); + } else if ("merged".equals(args[0]) || "report".equals(args[0]) || paste) { + long sampleTime = System.nanoTime() - timingStart; + int index = 0; + File timingFolder = new File("timings"); + timingFolder.mkdirs(); + File timings = new File(timingFolder, "timings.txt"); + ByteArrayOutputStream bout = ( paste ) ? new ByteArrayOutputStream() : null; + while (timings.exists()) timings = new File(timingFolder, "timings" + (++index) + ".txt"); + PrintStream fileTimings = null; + try { + fileTimings = ( paste ) ? new PrintStream( bout ) : new PrintStream( timings ); + + CustomTimingsHandler.printTimings(fileTimings); + fileTimings.println( "Sample time " + sampleTime + " (" + sampleTime / 1E9 + "s)" ); + + if ( paste ) + { + new PasteThread( sender, bout ).start(); + return; + } + + sender.sendMessage("Timings written to " + timings.getPath()); + sender.sendMessage( "Paste contents of file into form at http://www.spigotmc.org/go/timings to read results." ); + + } catch (IOException e) { + } finally { + if (fileTimings != null) { + fileTimings.close(); + } + } + } + } + // Spigot end + @Override public boolean execute(CommandSender sender, String currentAlias, String[] args) { if (!testPermission(sender)) return true; - if (args.length != 1) { + if (args.length < 1) { // Spigot sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); return false; } + if (true) { executeSpigotTimings(sender, args); return true; } // Spigot if (!sender.getServer().getPluginManager().useTimings()) { sender.sendMessage("Please enable timings by setting \"settings.plugin-profiling\" to true in bukkit.yml"); return true; @@ -118,4 +192,55 @@ } return ImmutableList.of(); } + + // Spigot start + private static class PasteThread extends Thread + { + + private final CommandSender sender; + private final ByteArrayOutputStream bout; + + public PasteThread(CommandSender sender, ByteArrayOutputStream bout) + { + super( "Timings paste thread" ); + this.sender = sender; + this.bout = bout; + } + + @Override + public synchronized void start() { + if (sender instanceof RemoteConsoleCommandSender) { + run(); + } else { + super.start(); + } + } + + @Override + public void run() + { + try + { + HttpURLConnection con = (HttpURLConnection) new URL( "https://timings.spigotmc.org/paste" ).openConnection(); + con.setDoOutput( true ); + con.setRequestMethod( "POST" ); + con.setInstanceFollowRedirects( false ); + + OutputStream out = con.getOutputStream(); + out.write( bout.toByteArray() ); + out.close(); + + com.google.gson.JsonObject location = new com.google.gson.Gson().fromJson(new java.io.InputStreamReader(con.getInputStream()), com.google.gson.JsonObject.class); + con.getInputStream().close(); + + String pasteID = location.get( "key" ).getAsString(); + sender.sendMessage( ChatColor.GREEN + "Timings results can be viewed at https://www.spigotmc.org/go/timings?url=" + pasteID ); + } catch ( IOException ex ) + { + sender.sendMessage( ChatColor.RED + "Error pasting timings, check your console for more information" ); + Bukkit.getServer().getLogger().log( Level.WARNING, "Could not paste timings", ex ); + } + } + } + // Spigot end }