More improvements to Timings, RCON now is no longer blocking!

Finally made timings accept "Callback style" reports, so plugins
can listen for when the report is done.

Added new Util interfaces, MessageCommandSender and BufferedCommandSender

This restores and improves using RCON to generate timings reports
This commit is contained in:
Aikar 2017-02-04 22:47:39 -05:00
parent f938ae30fd
commit d033b57b47
2 changed files with 199 additions and 143 deletions

View File

@ -1,4 +1,4 @@
From 54d8f0c3b52d8bd1d3e4afee2c6c3489da1c3577 Mon Sep 17 00:00:00 2001 From 134c514dd418485e6f07d20930dc0c4398dc76fd Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Mon, 29 Feb 2016 18:48:17 -0600 Date: Mon, 29 Feb 2016 18:48:17 -0600
Subject: [PATCH] Timings v2 Subject: [PATCH] Timings v2
@ -1184,10 +1184,10 @@ index 00000000..623dda49
+} +}
diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java
new file mode 100644 new file mode 100644
index 00000000..483e3669 index 00000000..0571c9e7
--- /dev/null --- /dev/null
+++ b/src/main/java/co/aikar/timings/Timings.java +++ b/src/main/java/co/aikar/timings/Timings.java
@@ -0,0 +1,274 @@ @@ -0,0 +1,284 @@
+/* +/*
+ * This file is licensed under the MIT License (MIT). + * This file is licensed under the MIT License (MIT).
+ * + *
@ -1215,6 +1215,7 @@ index 00000000..483e3669
+ +
+import com.google.common.base.Preconditions; +import com.google.common.base.Preconditions;
+import com.google.common.collect.EvictingQueue; +import com.google.common.collect.EvictingQueue;
+import org.apache.commons.lang.Validate;
+import org.bukkit.Bukkit; +import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender; +import org.bukkit.command.CommandSender;
+import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.Plugin;
@ -1431,7 +1432,16 @@ index 00000000..483e3669
+ if (sender == null) { + if (sender == null) {
+ sender = Bukkit.getConsoleSender(); + sender = Bukkit.getConsoleSender();
+ } + }
+ // Schedule report for end of tick + TimingsExport.requestingReport.add(sender);
+ }
+
+ /**
+ * Generates a report and sends it to the specified listener.
+ * Use with {@link org.bukkit.command.BufferedCommandSender} to get full response when done!
+ * @param sender The listener to send responses too.
+ */
+ public static void generateReport(TimingsReportListener sender) {
+ Validate.notNull(sender);
+ TimingsExport.requestingReport.add(sender); + TimingsExport.requestingReport.add(sender);
+ } + }
+ +
@ -1589,10 +1599,10 @@ index 00000000..56b10e89
+} +}
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
new file mode 100644 new file mode 100644
index 00000000..9dd36419 index 00000000..23a3daa8
--- /dev/null --- /dev/null
+++ b/src/main/java/co/aikar/timings/TimingsExport.java +++ b/src/main/java/co/aikar/timings/TimingsExport.java
@@ -0,0 +1,394 @@ @@ -0,0 +1,341 @@
+/* +/*
+ * This file is licensed under the MIT License (MIT). + * This file is licensed under the MIT License (MIT).
+ * + *
@ -1618,7 +1628,6 @@ index 00000000..9dd36419
+ */ + */
+package co.aikar.timings; +package co.aikar.timings;
+ +
+import com.google.common.base.Function;
+import com.google.common.collect.Lists; +import com.google.common.collect.Lists;
+import com.google.common.collect.Sets; +import com.google.common.collect.Sets;
+import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.StringUtils;
@ -1626,13 +1635,9 @@ index 00000000..9dd36419
+import org.bukkit.ChatColor; +import org.bukkit.ChatColor;
+import org.bukkit.Material; +import org.bukkit.Material;
+import org.bukkit.command.CommandSender; +import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.command.MultiMessageCommandSender;
+import org.bukkit.command.RemoteConsoleCommandSender;
+import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.MemorySection; +import org.bukkit.configuration.MemorySection;
+import org.bukkit.entity.EntityType; +import org.bukkit.entity.EntityType;
+import org.bukkit.plugin.Plugin;
+import org.json.simple.JSONObject; +import org.json.simple.JSONObject;
+import org.json.simple.JSONValue; +import org.json.simple.JSONValue;
+ +
@ -1640,7 +1645,6 @@ index 00000000..9dd36419
+import java.io.IOException; +import java.io.IOException;
+import java.io.InputStream; +import java.io.InputStream;
+import java.io.OutputStream; +import java.io.OutputStream;
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory; +import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean; +import java.lang.management.RuntimeMXBean;
+import java.net.HttpURLConnection; +import java.net.HttpURLConnection;
@ -1653,20 +1657,25 @@ index 00000000..9dd36419
+import java.util.zip.GZIPOutputStream; +import java.util.zip.GZIPOutputStream;
+ +
+import static co.aikar.timings.TimingsManager.HISTORY; +import static co.aikar.timings.TimingsManager.HISTORY;
+import static co.aikar.util.JSONUtil.*; +import static co.aikar.util.JSONUtil.appendObjectData;
+import static co.aikar.util.JSONUtil.createObject;
+import static co.aikar.util.JSONUtil.pair;
+import static co.aikar.util.JSONUtil.toArray;
+import static co.aikar.util.JSONUtil.toArrayMapper;
+import static co.aikar.util.JSONUtil.toObjectMapper;
+ +
+@SuppressWarnings({"rawtypes", "SuppressionAnnotation"}) +@SuppressWarnings({"rawtypes", "SuppressionAnnotation"})
+class TimingsExport extends Thread { +class TimingsExport extends Thread {
+ +
+ private final CommandSender sender; + private final TimingsReportListener listeners;
+ private final Map out; + private final Map out;
+ private final TimingHistory[] history; + private final TimingHistory[] history;
+ private static long lastReport = 0; + private static long lastReport = 0;
+ final static List<CommandSender> requestingReport = Lists.newArrayList(); + final static List<CommandSender> requestingReport = Lists.newArrayList();
+ +
+ private TimingsExport(CommandSender sender, Map out, TimingHistory[] history) { + private TimingsExport(TimingsReportListener listeners, Map out, TimingHistory[] history) {
+ super("Timings paste thread"); + super("Timings paste thread");
+ this.sender = sender; + this.listeners = listeners;
+ this.out = out; + this.out = out;
+ this.history = history; + this.history = history;
+ } + }
@ -1678,19 +1687,24 @@ index 00000000..9dd36419
+ if (requestingReport.isEmpty()) { + if (requestingReport.isEmpty()) {
+ return; + return;
+ } + }
+ CommandSender sender = new MultiMessageCommandSender(requestingReport); + TimingsReportListener listeners = new TimingsReportListener(requestingReport);
+ listeners.addConsoleIfNeeded();
+
+ requestingReport.clear(); + requestingReport.clear();
+ long now = System.currentTimeMillis(); + long now = System.currentTimeMillis();
+ final long lastReportDiff = now - lastReport; + final long lastReportDiff = now - lastReport;
+ if (lastReportDiff < 60000) { + if (lastReportDiff < 60000) {
+ sender.sendMessage(ChatColor.RED + "Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)"); + listeners.sendMessage(ChatColor.RED + "Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)");
+ listeners.done();
+ return; + return;
+ } + }
+ final long lastStartDiff = now - TimingsManager.timingStart; + final long lastStartDiff = now - TimingsManager.timingStart;
+ if (lastStartDiff < 180000) { + if (lastStartDiff < 180000) {
+ sender.sendMessage(ChatColor.RED + "Please wait at least 3 minutes before generating a Timings report. Unlike Timings v1, v2 benefits from longer timings and is not as useful with short timings. (" + (int)((180000 - lastStartDiff) / 1000) + " seconds)"); + listeners.sendMessage(ChatColor.RED + "Please wait at least 3 minutes before generating a Timings report. Unlike Timings v1, v2 benefits from longer timings and is not as useful with short timings. (" + (int)((180000 - lastStartDiff) / 1000) + " seconds)");
+ listeners.done();
+ return; + return;
+ } + }
+ listeners.sendMessage(ChatColor.GREEN + "Preparing Timings Report...");
+ lastReport = now; + lastReport = now;
+ Map parent = createObject( + Map parent = createObject(
+ // Get some basic system details about the server + // Get some basic system details about the server
@ -1722,12 +1736,7 @@ index 00000000..9dd36419
+ pair("cpu", runtime.availableProcessors()), + pair("cpu", runtime.availableProcessors()),
+ pair("runtime", ManagementFactory.getRuntimeMXBean().getUptime()), + pair("runtime", ManagementFactory.getRuntimeMXBean().getUptime()),
+ pair("flags", StringUtils.join(runtimeBean.getInputArguments(), " ")), + pair("flags", StringUtils.join(runtimeBean.getInputArguments(), " ")),
+ pair("gc", toObjectMapper(ManagementFactory.getGarbageCollectorMXBeans(), new Function<GarbageCollectorMXBean, JSONPair>() { + pair("gc", toObjectMapper(ManagementFactory.getGarbageCollectorMXBeans(), input -> pair(input.getName(), toArray(input.getCollectionCount(), input.getCollectionTime()))))
+ @Override
+ public JSONPair apply(GarbageCollectorMXBean input) {
+ return pair(input.getName(), toArray(input.getCollectionCount(), input.getCollectionTime()));
+ }
+ }))
+ ) + )
+ ); + );
+ +
@ -1763,49 +1772,24 @@ index 00000000..9dd36419
+ +
+ parent.put("idmap", createObject( + parent.put("idmap", createObject(
+ pair("groups", toObjectMapper( + pair("groups", toObjectMapper(
+ TimingIdentifier.GROUP_MAP.values(), new Function<TimingIdentifier.TimingGroup, JSONPair>() { + TimingIdentifier.GROUP_MAP.values(), group -> pair(group.id, group.name))),
+ @Override
+ public JSONPair apply(TimingIdentifier.TimingGroup group) {
+ return pair(group.id, group.name);
+ }
+ })),
+ pair("handlers", handlers), + pair("handlers", handlers),
+ pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), new Function<Map.Entry<String, Integer>, JSONPair>() { + pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), input -> pair(input.getValue(), input.getKey()))),
+ @Override
+ public JSONPair apply(Map.Entry<String, Integer> input) {
+ return pair(input.getValue(), input.getKey());
+ }
+ })),
+ pair("tileentity", + pair("tileentity",
+ toObjectMapper(tileEntityTypeSet, new Function<Material, JSONPair>() { + toObjectMapper(tileEntityTypeSet, input -> pair(input.getId(), input.name()))),
+ @Override
+ public JSONPair apply(Material input) {
+ return pair(input.getId(), input.name());
+ }
+ })),
+ pair("entity", + pair("entity",
+ toObjectMapper(entityTypeSet, new Function<EntityType, JSONPair>() { + toObjectMapper(entityTypeSet, input -> pair(input.getTypeId(), input.name())))
+ @Override
+ public JSONPair apply(EntityType input) {
+ return pair(input.getTypeId(), input.name());
+ }
+ }))
+ )); + ));
+ +
+ // Information about loaded plugins + // Information about loaded plugins
+ +
+ parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(), + parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(),
+ new Function<Plugin, JSONPair>() { + plugin -> pair(plugin.getName(), createObject(
+ @Override + pair("version", plugin.getDescription().getVersion()),
+ public JSONPair apply(Plugin plugin) { + pair("description", String.valueOf(plugin.getDescription().getDescription()).trim()),
+ return pair(plugin.getName(), createObject( + pair("website", plugin.getDescription().getWebsite()),
+ pair("version", plugin.getDescription().getVersion()), + pair("authors", StringUtils.join(plugin.getDescription().getAuthors(), ", "))
+ pair("description", String.valueOf(plugin.getDescription().getDescription()).trim()), + ))));
+ pair("website", plugin.getDescription().getWebsite()),
+ pair("authors", StringUtils.join(plugin.getDescription().getAuthors(), ", "))
+ ));
+ }
+ }));
+ +
+ +
+ +
@ -1817,7 +1801,7 @@ index 00000000..9dd36419
+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)) + pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null))
+ )); + ));
+ +
+ new TimingsExport(sender, parent, history).start(); + new TimingsExport(listeners, parent, history).start();
+ } + }
+ +
+ static long getCost() { + static long getCost() {
@ -1874,12 +1858,7 @@ index 00000000..9dd36419
+ if (!(val instanceof MemorySection)) { + if (!(val instanceof MemorySection)) {
+ if (val instanceof List) { + if (val instanceof List) {
+ Iterable<Object> v = (Iterable<Object>) val; + Iterable<Object> v = (Iterable<Object>) val;
+ return toArrayMapper(v, new Function<Object, Object>() { + return toArrayMapper(v, input -> valAsJSON(input, parentKey));
+ @Override
+ public Object apply(Object input) {
+ return valAsJSON(input, parentKey);
+ }
+ });
+ } else { + } else {
+ return val.toString(); + return val.toString();
+ } + }
@ -1888,30 +1867,9 @@ index 00000000..9dd36419
+ } + }
+ } + }
+ +
+ @SuppressWarnings("CallToThreadRun")
+ @Override
+ public synchronized void start() {
+ if (sender instanceof RemoteConsoleCommandSender) {
+ sender.sendMessage(ChatColor.RED + "Warning: Timings report done over RCON will cause lag spikes.");
+ sender.sendMessage(ChatColor.RED + "You should use " + ChatColor.YELLOW +
+ "/timings report" + ChatColor.RED + " in game or console.");
+ run();
+ } else {
+ super.start();
+ }
+ }
+
+ @Override + @Override
+ public void run() { + public void run() {
+ sender.sendMessage(ChatColor.GREEN + "Preparing Timings Report..."); + out.put("data", toArrayMapper(history, TimingHistory::export));
+
+
+ out.put("data", toArrayMapper(history, new Function<TimingHistory, Object>() {
+ @Override
+ public Object apply(TimingHistory input) {
+ return input.export();
+ }
+ }));
+ +
+ +
+ String response = null; + String response = null;
@ -1936,9 +1894,9 @@ index 00000000..9dd36419
+ response = getResponse(con); + response = getResponse(con);
+ +
+ if (con.getResponseCode() != 302) { + if (con.getResponseCode() != 302) {
+ sender.sendMessage( + listeners.sendMessage(
+ ChatColor.RED + "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage()); + ChatColor.RED + "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage());
+ sender.sendMessage(ChatColor.RED + "Check your logs for more information"); + listeners.sendMessage(ChatColor.RED + "Check your logs for more information");
+ if (response != null) { + if (response != null) {
+ Bukkit.getLogger().log(Level.SEVERE, response); + Bukkit.getLogger().log(Level.SEVERE, response);
+ } + }
@ -1946,20 +1904,19 @@ index 00000000..9dd36419
+ } + }
+ +
+ String location = con.getHeaderField("Location"); + String location = con.getHeaderField("Location");
+ sender.sendMessage(ChatColor.GREEN + "View Timings Report: " + location); + listeners.sendMessage(ChatColor.GREEN + "View Timings Report: " + location);
+ if (!(sender instanceof ConsoleCommandSender)) {
+ Bukkit.getLogger().log(Level.INFO, "View Timings Report: " + location);
+ }
+ +
+ if (response != null && !response.isEmpty()) { + if (response != null && !response.isEmpty()) {
+ Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response); + Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response);
+ } + }
+ } catch (IOException ex) { + } catch (IOException ex) {
+ sender.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information"); + listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
+ if (response != null) { + if (response != null) {
+ Bukkit.getLogger().log(Level.SEVERE, response); + Bukkit.getLogger().log(Level.SEVERE, response);
+ } + }
+ Bukkit.getLogger().log(Level.SEVERE, "Could not paste timings", ex); + Bukkit.getLogger().log(Level.SEVERE, "Could not paste timings", ex);
+ } finally {
+ this.listeners.done();
+ } + }
+ } + }
+ +
@ -1977,7 +1934,7 @@ index 00000000..9dd36419
+ return bos.toString(); + return bos.toString();
+ +
+ } catch (IOException ex) { + } catch (IOException ex) {
+ sender.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information"); + listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
+ Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex); + Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex);
+ return null; + return null;
+ } finally { + } finally {
@ -2189,6 +2146,74 @@ index 00000000..58ed35e0
+ return null; + return null;
+ } + }
+} +}
diff --git a/src/main/java/co/aikar/timings/TimingsReportListener.java b/src/main/java/co/aikar/timings/TimingsReportListener.java
new file mode 100644
index 00000000..4d492d4b
--- /dev/null
+++ b/src/main/java/co/aikar/timings/TimingsReportListener.java
@@ -0,0 +1,62 @@
+package co.aikar.timings;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.Validate;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.command.MessageCommandSender;
+import org.bukkit.command.RemoteConsoleCommandSender;
+
+import java.util.List;
+
+@SuppressWarnings("WeakerAccess")
+public class TimingsReportListener implements MessageCommandSender {
+ private final List<CommandSender> senders;
+ private final Runnable onDone;
+
+ public TimingsReportListener(CommandSender senders) {
+ this(senders, null);
+ }
+ public TimingsReportListener(CommandSender sender, Runnable onDone) {
+ this(Lists.newArrayList(sender), onDone);
+ }
+ public TimingsReportListener(List<CommandSender> senders) {
+ this(senders, null);
+ }
+ public TimingsReportListener(List<CommandSender> senders, Runnable onDone) {
+ Validate.notNull(senders);
+ Validate.notEmpty(senders);
+
+ this.senders = Lists.newArrayList(senders);
+ this.onDone = onDone;
+ }
+
+ public void done() {
+ if (onDone != null) {
+ onDone.run();
+ }
+ for (CommandSender sender : senders) {
+ if (sender instanceof TimingsReportListener) {
+ ((TimingsReportListener) sender).done();
+ }
+ }
+ }
+
+ @Override
+ public void sendMessage(String message) {
+ senders.forEach((sender) -> sender.sendMessage(message));
+ }
+
+ public void addConsoleIfNeeded() {
+ boolean hasConsole = false;
+ for (CommandSender sender : this.senders) {
+ if (sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
+ hasConsole = true;
+ }
+ }
+ if (!hasConsole) {
+ this.senders.add(Bukkit.getConsoleSender());
+ }
+ }
+}
diff --git a/src/main/java/co/aikar/timings/UnsafeTimingHandler.java b/src/main/java/co/aikar/timings/UnsafeTimingHandler.java diff --git a/src/main/java/co/aikar/timings/UnsafeTimingHandler.java b/src/main/java/co/aikar/timings/UnsafeTimingHandler.java
new file mode 100644 new file mode 100644
index 00000000..5edaba12 index 00000000..5edaba12
@ -2940,6 +2965,30 @@ index 120dba25..77cfe561 100644
/** /**
* Sends the component to the player * Sends the component to the player
* *
diff --git a/src/main/java/org/bukkit/command/BufferedCommandSender.java b/src/main/java/org/bukkit/command/BufferedCommandSender.java
new file mode 100644
index 00000000..fd452bce
--- /dev/null
+++ b/src/main/java/org/bukkit/command/BufferedCommandSender.java
@@ -0,0 +1,18 @@
+package org.bukkit.command;
+
+public class BufferedCommandSender implements MessageCommandSender {
+ private final StringBuffer buffer = new StringBuffer();
+ @Override
+ public void sendMessage(String message) {
+ buffer.append(message);
+ buffer.append("\n");
+ }
+
+ public String getBuffer() {
+ return buffer.toString();
+ }
+
+ public void reset() {
+ this.buffer.setLength(0);
+ }
+}
diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java
index 08a9739f..347d2189 100644 index 08a9739f..347d2189 100644
--- a/src/main/java/org/bukkit/command/Command.java --- a/src/main/java/org/bukkit/command/Command.java
@ -2992,17 +3041,15 @@ index 3f07d7f4..f89ad075 100644
private static boolean inRange(int i, int j, int k) { private static boolean inRange(int i, int j, int k) {
return i >= j && i <= k; return i >= j && i <= k;
} }
diff --git a/src/main/java/org/bukkit/command/MultiMessageCommandSender.java b/src/main/java/org/bukkit/command/MultiMessageCommandSender.java diff --git a/src/main/java/org/bukkit/command/MessageCommandSender.java b/src/main/java/org/bukkit/command/MessageCommandSender.java
new file mode 100644 new file mode 100644
index 00000000..7b512fd4 index 00000000..66232339
--- /dev/null --- /dev/null
+++ b/src/main/java/org/bukkit/command/MultiMessageCommandSender.java +++ b/src/main/java/org/bukkit/command/MessageCommandSender.java
@@ -0,0 +1,114 @@ @@ -0,0 +1,99 @@
+package org.bukkit.command; +package org.bukkit.command;
+ +
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.NotImplementedException; +import org.apache.commons.lang.NotImplementedException;
+import org.apache.commons.lang.Validate;
+import org.bukkit.Bukkit; +import org.bukkit.Bukkit;
+import org.bukkit.Server; +import org.bukkit.Server;
+import org.bukkit.permissions.Permission; +import org.bukkit.permissions.Permission;
@ -3010,105 +3057,92 @@ index 00000000..7b512fd4
+import org.bukkit.permissions.PermissionAttachmentInfo; +import org.bukkit.permissions.PermissionAttachmentInfo;
+import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.Plugin;
+ +
+import java.util.List;
+import java.util.Set; +import java.util.Set;
+ +
+/** +/**
+ * Used for proxying messages to multiple senders. + * For when all you care about is just messaging
+ * Do not use this for anything else but messages.
+ */ + */
+public class MultiMessageCommandSender implements CommandSender { +public interface MessageCommandSender extends CommandSender {
+ private final List<CommandSender> senders;
+ +
+ public MultiMessageCommandSender(List<CommandSender> senders) { + @Override
+ Validate.notNull(senders); + default void sendMessage(String[] messages) {
+ Validate.notEmpty(senders); + for (String message : messages) {
+ + sendMessage(message);
+ this.senders = Lists.newArrayList(senders); + }
+ } + }
+ +
+ @Override + @Override
+ public void sendMessage(String message) { + default Server getServer() {
+ senders.forEach((sender) -> sender.sendMessage(message));
+ }
+
+ @Override
+ public void sendMessage(String[] messages) {
+ senders.forEach((sender) -> sender.sendMessage(messages));
+ }
+
+ @Override
+ public Server getServer() {
+ return Bukkit.getServer(); + return Bukkit.getServer();
+ } + }
+ +
+ @Override + @Override
+ public String getName() { + default String getName() {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public boolean isOp() { + default boolean isOp() {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public void setOp(boolean value) { + default void setOp(boolean value) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public boolean isPermissionSet(String name) { + default boolean isPermissionSet(String name) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public boolean isPermissionSet(Permission perm) { + default boolean isPermissionSet(Permission perm) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public boolean hasPermission(String name) { + default boolean hasPermission(String name) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public boolean hasPermission(Permission perm) { + default boolean hasPermission(Permission perm) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) { + default PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public PermissionAttachment addAttachment(Plugin plugin) { + default PermissionAttachment addAttachment(Plugin plugin) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) { + default PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public PermissionAttachment addAttachment(Plugin plugin, int ticks) { + default PermissionAttachment addAttachment(Plugin plugin, int ticks) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public void removeAttachment(PermissionAttachment attachment) { + default void removeAttachment(PermissionAttachment attachment) {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public void recalculatePermissions() { + default void recalculatePermissions() {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+ +
+ @Override + @Override
+ public Set<PermissionAttachmentInfo> getEffectivePermissions() { + default Set<PermissionAttachmentInfo> getEffectivePermissions() {
+ throw new NotImplementedException(); + throw new NotImplementedException();
+ } + }
+} +}

View File

@ -1,11 +1,11 @@
From fab6746b634e849bb0effc92deb503dc84e72eac Mon Sep 17 00:00:00 2001 From f6a0b22a39ad826143911fdb4e4127297e1cf862 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Thu, 3 Mar 2016 04:00:11 -0600 Date: Thu, 3 Mar 2016 04:00:11 -0600
Subject: [PATCH] Timings v2 Subject: [PATCH] Timings v2
diff --git a/pom.xml b/pom.xml diff --git a/pom.xml b/pom.xml
index 0e88ae2a7..31b8401aa 100644 index 8b96966d8..8d1e8680b 100644
--- a/pom.xml --- a/pom.xml
+++ b/pom.xml +++ b/pom.xml
@@ -66,6 +66,12 @@ @@ -66,6 +66,12 @@
@ -493,7 +493,7 @@ index 81fc04ed3..bd3b16025 100644
private void z() { private void z() {
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
index 87c07f2be..e18fb875f 100644 index daf2c0a67..3ba489d4f 100644
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
@@ -195,7 +195,7 @@ public class ChunkProviderServer implements IChunkProvider { @@ -195,7 +195,7 @@ public class ChunkProviderServer implements IChunkProvider {
@ -555,7 +555,7 @@ index a97e7d3c2..4890023d7 100644
// return chunk; // CraftBukkit // return chunk; // CraftBukkit
} }
diff --git a/src/main/java/net/minecraft/server/DedicatedServer.java b/src/main/java/net/minecraft/server/DedicatedServer.java diff --git a/src/main/java/net/minecraft/server/DedicatedServer.java b/src/main/java/net/minecraft/server/DedicatedServer.java
index cb83e4f56..4dab9e962 100644 index cb83e4f56..e6819139f 100644
--- a/src/main/java/net/minecraft/server/DedicatedServer.java --- a/src/main/java/net/minecraft/server/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/DedicatedServer.java
@@ -23,7 +23,7 @@ import java.io.PrintStream; @@ -23,7 +23,7 @@ import java.io.PrintStream;
@ -585,6 +585,28 @@ index cb83e4f56..4dab9e962 100644
} }
public boolean aa() { public boolean aa() {
@@ -692,7 +692,20 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
return remoteControlCommandListener.getMessages();
}
};
- processQueue.add(waitable);
+ // Paper start
+ if (s.toLowerCase().startsWith("timings") && s.toLowerCase().matches("timings (report|paste|get|merged|seperate)")) {
+ org.bukkit.command.BufferedCommandSender sender = new org.bukkit.command.BufferedCommandSender();
+ waitable = new Waitable<String>() {
+ @Override
+ protected String evaluate() {
+ return sender.getBuffer();
+ }
+ };
+ co.aikar.timings.Timings.generateReport(new co.aikar.timings.TimingsReportListener(sender, waitable));
+ } else {
+ processQueue.add(waitable);
+ }
+ // Paper end
try {
return waitable.get();
} catch (java.util.concurrent.ExecutionException e) {
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index e7b1ebbe3..05312c6ac 100644 index e7b1ebbe3..05312c6ac 100644
--- a/src/main/java/net/minecraft/server/Entity.java --- a/src/main/java/net/minecraft/server/Entity.java
@ -1832,5 +1854,5 @@ index c32d44df0..5c2fb0058 100644
} }
} }
-- --
2.11.0.windows.3 2.11.0