mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-29 22:13:42 +01:00
Add more information to Timing Reports
Still needs front end changes to see it yet though. 1) Adds Game Rules per world 2) Adds View distances per world 3) Removes extra garbage on lambda task names 4) Adds more memory information such as native load 5) Adds load average for non crap operating systems. 6) Fixes online mode showing false when privacy=true 7) Adds Data packs loaded
This commit is contained in:
parent
f4a47db699
commit
e470f1effe
@ -6,7 +6,7 @@ Subject: [PATCH] Timings v2
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/FullServerTickHandler.java b/src/main/java/co/aikar/timings/FullServerTickHandler.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..65ff5403cbc894215089626450252a050dd13119
|
||||
index 0000000000000000000000000000000000000000..dfaa266ff53e43ad48dc5a5a5657fe70600f539a
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/co/aikar/timings/FullServerTickHandler.java
|
||||
@@ -0,0 +1,85 @@
|
||||
@ -88,7 +88,7 @@ index 0000000000000000000000000000000000000000..65ff5403cbc894215089626450252a05
|
||||
+ TimingsManager.HISTORY.add(new TimingHistory());
|
||||
+ TimingsManager.resetTimings();
|
||||
+ }
|
||||
+ TimingsExport.reportTimings();
|
||||
+ Bukkit.getUnsafe().reportTimings();
|
||||
+ }
|
||||
+
|
||||
+ boolean isViolated() {
|
||||
@ -1255,10 +1255,10 @@ index 0000000000000000000000000000000000000000..df142a89b8c43acb81eb383eac0ef048
|
||||
+}
|
||||
diff --git a/src/main/java/co/aikar/timings/Timings.java b/src/main/java/co/aikar/timings/Timings.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0b34e0d0174b7d92a17699538d5f3fe5196f82b9
|
||||
index 0000000000000000000000000000000000000000..da76e1aaee1dee794e38ddd4e0a28e0071e90bbf
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/co/aikar/timings/Timings.java
|
||||
@@ -0,0 +1,293 @@
|
||||
@@ -0,0 +1,296 @@
|
||||
+/*
|
||||
+ * This file is licensed under the MIT License (MIT).
|
||||
+ *
|
||||
@ -1286,11 +1286,13 @@ index 0000000000000000000000000000000000000000..0b34e0d0174b7d92a17699538d5f3fe5
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import com.google.common.collect.EvictingQueue;
|
||||
+import com.google.common.collect.Lists;
|
||||
+import org.apache.commons.lang.Validate;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.plugin.Plugin;
|
||||
+
|
||||
+import java.util.List;
|
||||
+import java.util.Queue;
|
||||
+import java.util.logging.Level;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
@ -1299,6 +1301,7 @@ index 0000000000000000000000000000000000000000..0b34e0d0174b7d92a17699538d5f3fe5
|
||||
+@SuppressWarnings({"UnusedDeclaration", "WeakerAccess", "SameParameterValue"})
|
||||
+public final class Timings {
|
||||
+
|
||||
+ final static List<CommandSender> requestingReport = Lists.newArrayList();
|
||||
+ private static final int MAX_HISTORY_FRAMES = 12;
|
||||
+ public static final Timing NULL_HANDLER = new NullTimingHandler();
|
||||
+ static boolean timingsEnabled = false;
|
||||
@ -1509,7 +1512,7 @@ index 0000000000000000000000000000000000000000..0b34e0d0174b7d92a17699538d5f3fe5
|
||||
+ if (sender == null) {
|
||||
+ sender = Bukkit.getConsoleSender();
|
||||
+ }
|
||||
+ TimingsExport.requestingReport.add(sender);
|
||||
+ requestingReport.add(sender);
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
@ -1519,7 +1522,7 @@ index 0000000000000000000000000000000000000000..0b34e0d0174b7d92a17699538d5f3fe5
|
||||
+ */
|
||||
+ public static void generateReport(@NotNull TimingsReportListener sender) {
|
||||
+ Validate.notNull(sender);
|
||||
+ TimingsExport.requestingReport.add(sender);
|
||||
+ requestingReport.add(sender);
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
@ -1554,10 +1557,10 @@ index 0000000000000000000000000000000000000000..0b34e0d0174b7d92a17699538d5f3fe5
|
||||
+}
|
||||
diff --git a/src/main/java/co/aikar/timings/TimingsCommand.java b/src/main/java/co/aikar/timings/TimingsCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c0d8f2016bbc0257c8eb4888508e8f50d7c4790f
|
||||
index 0000000000000000000000000000000000000000..f7c2245a310a084367ff25db539b3c967d5cb141
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/co/aikar/timings/TimingsCommand.java
|
||||
@@ -0,0 +1,122 @@
|
||||
@@ -0,0 +1,119 @@
|
||||
+/*
|
||||
+ * This file is licensed under the MIT License (MIT).
|
||||
+ *
|
||||
@ -1649,9 +1652,6 @@ index 0000000000000000000000000000000000000000..c0d8f2016bbc0257c8eb4888508e8f50
|
||||
+ lastResetAttempt = now;
|
||||
+ sender.sendMessage(ChatColor.RED + "WARNING: Timings v2 should not be reset. If you are encountering lag, please wait 3 minutes and then issue a report. The best timings will include 10+ minutes, with data before and after your lag period. If you really want to reset, run this command again within 30 seconds.");
|
||||
+ }
|
||||
+
|
||||
+ } else if ("cost".equals(arg)) {
|
||||
+ sender.sendMessage("Timings cost: " + TimingsExport.getCost());
|
||||
+ } else if (
|
||||
+ "paste".equalsIgnoreCase(arg) ||
|
||||
+ "report".equalsIgnoreCase(arg) ||
|
||||
@ -1680,367 +1680,6 @@ index 0000000000000000000000000000000000000000..c0d8f2016bbc0257c8eb4888508e8f50
|
||||
+ return ImmutableList.of();
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..93d5a3f97a1b2b3a1cd2731d48e8ebd01d29aa91
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
@@ -0,0 +1,355 @@
|
||||
+/*
|
||||
+ * This file is licensed under the MIT License (MIT).
|
||||
+ *
|
||||
+ * Copyright (c) 2014 Daniel Ennis <http://aikar.co>
|
||||
+ *
|
||||
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
+ * of this software and associated documentation files (the "Software"), to deal
|
||||
+ * in the Software without restriction, including without limitation the rights
|
||||
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
+ * copies of the Software, and to permit persons to whom the Software is
|
||||
+ * furnished to do so, subject to the following conditions:
|
||||
+ *
|
||||
+ * The above copyright notice and this permission notice shall be included in
|
||||
+ * all copies or substantial portions of the Software.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
+ * THE SOFTWARE.
|
||||
+ */
|
||||
+package co.aikar.timings;
|
||||
+
|
||||
+import com.google.common.collect.Lists;
|
||||
+import com.google.common.collect.Sets;
|
||||
+import org.apache.commons.lang.StringUtils;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.bukkit.ChatColor;
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.command.CommandSender;
|
||||
+import org.bukkit.configuration.ConfigurationSection;
|
||||
+import org.bukkit.configuration.MemorySection;
|
||||
+import org.bukkit.entity.EntityType;
|
||||
+import org.json.simple.JSONObject;
|
||||
+import org.json.simple.JSONValue;
|
||||
+
|
||||
+import java.io.ByteArrayOutputStream;
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.io.OutputStream;
|
||||
+import java.lang.management.ManagementFactory;
|
||||
+import java.lang.management.RuntimeMXBean;
|
||||
+import java.net.HttpURLConnection;
|
||||
+import java.net.InetAddress;
|
||||
+import java.net.URL;
|
||||
+import java.util.List;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+import java.util.logging.Level;
|
||||
+import java.util.zip.GZIPOutputStream;
|
||||
+
|
||||
+import static co.aikar.timings.TimingsManager.HISTORY;
|
||||
+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"})
|
||||
+class TimingsExport extends Thread {
|
||||
+
|
||||
+ private final TimingsReportListener listeners;
|
||||
+ private final Map out;
|
||||
+ private final TimingHistory[] history;
|
||||
+ private static long lastReport = 0;
|
||||
+ final static List<CommandSender> requestingReport = Lists.newArrayList();
|
||||
+
|
||||
+ private TimingsExport(TimingsReportListener listeners, Map out, TimingHistory[] history) {
|
||||
+ super("Timings paste thread");
|
||||
+ this.listeners = listeners;
|
||||
+ this.out = out;
|
||||
+ this.history = history;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Checks if any pending reports are being requested, and builds one if needed.
|
||||
+ */
|
||||
+ static void reportTimings() {
|
||||
+ if (requestingReport.isEmpty()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ TimingsReportListener listeners = new TimingsReportListener(requestingReport);
|
||||
+ listeners.addConsoleIfNeeded();
|
||||
+
|
||||
+ requestingReport.clear();
|
||||
+ long now = System.currentTimeMillis();
|
||||
+ final long lastReportDiff = now - lastReport;
|
||||
+ if (lastReportDiff < 60000) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)");
|
||||
+ listeners.done();
|
||||
+ return;
|
||||
+ }
|
||||
+ final long lastStartDiff = now - TimingsManager.timingStart;
|
||||
+ if (lastStartDiff < 180000) {
|
||||
+ 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;
|
||||
+ }
|
||||
+ listeners.sendMessage(ChatColor.GREEN + "Preparing Timings Report...");
|
||||
+ lastReport = now;
|
||||
+ Map parent = createObject(
|
||||
+ // Get some basic system details about the server
|
||||
+ pair("version", Bukkit.getVersion()),
|
||||
+ pair("maxplayers", Bukkit.getMaxPlayers()),
|
||||
+ pair("start", TimingsManager.timingStart / 1000),
|
||||
+ pair("end", System.currentTimeMillis() / 1000),
|
||||
+ pair("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000)
|
||||
+ );
|
||||
+ if (!TimingsManager.privacy) {
|
||||
+ appendObjectData(parent,
|
||||
+ pair("server", Bukkit.getUnsafe().getTimingsServerName()),
|
||||
+ pair("motd", Bukkit.getServer().getMotd()),
|
||||
+ pair("online-mode", Bukkit.getServer().getOnlineMode()),
|
||||
+ pair("icon", Bukkit.getServer().getServerIcon().getData())
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ final Runtime runtime = Runtime.getRuntime();
|
||||
+ RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
|
||||
+
|
||||
+ parent.put("system", createObject(
|
||||
+ pair("timingcost", getCost()),
|
||||
+ pair("name", System.getProperty("os.name")),
|
||||
+ pair("version", System.getProperty("os.version")),
|
||||
+ pair("jvmversion", System.getProperty("java.version")),
|
||||
+ pair("arch", System.getProperty("os.arch")),
|
||||
+ pair("maxmem", runtime.maxMemory()),
|
||||
+ pair("cpu", runtime.availableProcessors()),
|
||||
+ pair("runtime", ManagementFactory.getRuntimeMXBean().getUptime()),
|
||||
+ pair("flags", StringUtils.join(runtimeBean.getInputArguments(), " ")),
|
||||
+ pair("gc", toObjectMapper(ManagementFactory.getGarbageCollectorMXBeans(), input -> pair(input.getName(), toArray(input.getCollectionCount(), input.getCollectionTime()))))
|
||||
+ )
|
||||
+ );
|
||||
+
|
||||
+ Set<Material> tileEntityTypeSet = Sets.newHashSet();
|
||||
+ Set<EntityType> entityTypeSet = Sets.newHashSet();
|
||||
+
|
||||
+ int size = HISTORY.size();
|
||||
+ TimingHistory[] history = new TimingHistory[size + 1];
|
||||
+ int i = 0;
|
||||
+ for (TimingHistory timingHistory : HISTORY) {
|
||||
+ tileEntityTypeSet.addAll(timingHistory.tileEntityTypeSet);
|
||||
+ entityTypeSet.addAll(timingHistory.entityTypeSet);
|
||||
+ history[i++] = timingHistory;
|
||||
+ }
|
||||
+
|
||||
+ history[i] = new TimingHistory(); // Current snapshot
|
||||
+ tileEntityTypeSet.addAll(history[i].tileEntityTypeSet);
|
||||
+ entityTypeSet.addAll(history[i].entityTypeSet);
|
||||
+
|
||||
+
|
||||
+ Map handlers = createObject();
|
||||
+ Map groupData;
|
||||
+ synchronized (TimingIdentifier.GROUP_MAP) {
|
||||
+ for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) {
|
||||
+ synchronized (group.handlers) {
|
||||
+ for (TimingHandler id : group.handlers) {
|
||||
+
|
||||
+ if (!id.isTimed() && !id.isSpecial()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ String name = id.identifier.name;
|
||||
+ if (name.startsWith("##")) {
|
||||
+ name = name.substring(3);
|
||||
+ }
|
||||
+ handlers.put(id.id, toArray(
|
||||
+ group.id,
|
||||
+ name
|
||||
+ ));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ groupData = toObjectMapper(
|
||||
+ TimingIdentifier.GROUP_MAP.values(), group -> pair(group.id, group.name));
|
||||
+ }
|
||||
+
|
||||
+ parent.put("idmap", createObject(
|
||||
+ pair("groups", groupData),
|
||||
+ pair("handlers", handlers),
|
||||
+ pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), input -> pair(input.getValue(), input.getKey()))),
|
||||
+ pair("tileentity",
|
||||
+ toObjectMapper(tileEntityTypeSet, input -> pair(input.ordinal(), input.name()))),
|
||||
+ pair("entity",
|
||||
+ toObjectMapper(entityTypeSet, input -> pair(input.ordinal(), input.name())))
|
||||
+ ));
|
||||
+
|
||||
+ // Information about loaded plugins
|
||||
+
|
||||
+ parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(),
|
||||
+ plugin -> pair(plugin.getName(), createObject(
|
||||
+ pair("version", plugin.getDescription().getVersion()),
|
||||
+ pair("description", String.valueOf(plugin.getDescription().getDescription()).trim()),
|
||||
+ pair("website", plugin.getDescription().getWebsite()),
|
||||
+ pair("authors", StringUtils.join(plugin.getDescription().getAuthors(), ", "))
|
||||
+ ))));
|
||||
+
|
||||
+
|
||||
+
|
||||
+ // Information on the users Config
|
||||
+
|
||||
+ parent.put("config", createObject(
|
||||
+ pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)),
|
||||
+ pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)),
|
||||
+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null))
|
||||
+ ));
|
||||
+
|
||||
+ new TimingsExport(listeners, parent, history).start();
|
||||
+ }
|
||||
+
|
||||
+ static long getCost() {
|
||||
+ // Benchmark the users System.nanotime() for cost basis
|
||||
+ int passes = 100;
|
||||
+ TimingHandler SAMPLER1 = Timings.ofSafe("Timings Sampler 1");
|
||||
+ TimingHandler SAMPLER2 = Timings.ofSafe("Timings Sampler 2");
|
||||
+ TimingHandler SAMPLER3 = Timings.ofSafe("Timings Sampler 3");
|
||||
+ TimingHandler SAMPLER4 = Timings.ofSafe("Timings Sampler 4");
|
||||
+ TimingHandler SAMPLER5 = Timings.ofSafe("Timings Sampler 5");
|
||||
+ TimingHandler SAMPLER6 = Timings.ofSafe("Timings Sampler 6");
|
||||
+
|
||||
+ long start = System.nanoTime();
|
||||
+ for (int i = 0; i < passes; i++) {
|
||||
+ SAMPLER1.startTiming();
|
||||
+ SAMPLER2.startTiming();
|
||||
+ SAMPLER3.startTiming();
|
||||
+ SAMPLER3.stopTiming();
|
||||
+ SAMPLER4.startTiming();
|
||||
+ SAMPLER5.startTiming();
|
||||
+ SAMPLER6.startTiming();
|
||||
+ SAMPLER6.stopTiming();
|
||||
+ SAMPLER5.stopTiming();
|
||||
+ SAMPLER4.stopTiming();
|
||||
+ SAMPLER2.stopTiming();
|
||||
+ SAMPLER1.stopTiming();
|
||||
+ }
|
||||
+ long timingsCost = (System.nanoTime() - start) / passes / 6;
|
||||
+ SAMPLER1.reset(true);
|
||||
+ SAMPLER2.reset(true);
|
||||
+ SAMPLER3.reset(true);
|
||||
+ SAMPLER4.reset(true);
|
||||
+ SAMPLER5.reset(true);
|
||||
+ SAMPLER6.reset(true);
|
||||
+ return timingsCost;
|
||||
+ }
|
||||
+
|
||||
+ private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) {
|
||||
+
|
||||
+ JSONObject object = new JSONObject();
|
||||
+ for (String key : config.getKeys(false)) {
|
||||
+ String fullKey = (parentKey != null ? parentKey + "." + key : key);
|
||||
+ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ final Object val = config.get(key);
|
||||
+
|
||||
+ object.put(key, valAsJSON(val, fullKey));
|
||||
+ }
|
||||
+ return object;
|
||||
+ }
|
||||
+
|
||||
+ private static Object valAsJSON(Object val, final String parentKey) {
|
||||
+ if (!(val instanceof MemorySection)) {
|
||||
+ if (val instanceof List) {
|
||||
+ Iterable<Object> v = (Iterable<Object>) val;
|
||||
+ return toArrayMapper(v, input -> valAsJSON(input, parentKey));
|
||||
+ } else {
|
||||
+ return String.valueOf(val);
|
||||
+ }
|
||||
+ } else {
|
||||
+ return mapAsJSON((ConfigurationSection) val, parentKey);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void run() {
|
||||
+ out.put("data", toArrayMapper(history, TimingHistory::export));
|
||||
+
|
||||
+
|
||||
+ String response = null;
|
||||
+ String timingsURL = null;
|
||||
+ try {
|
||||
+ HttpURLConnection con = (HttpURLConnection) new URL("http://timings.aikar.co/post").openConnection();
|
||||
+ con.setDoOutput(true);
|
||||
+ String hostName = "BrokenHost";
|
||||
+ try {
|
||||
+ hostName = InetAddress.getLocalHost().getHostName();
|
||||
+ } catch (Exception ignored) {}
|
||||
+ con.setRequestProperty("User-Agent", "Paper/" + Bukkit.getUnsafe().getTimingsServerName() + "/" + hostName);
|
||||
+ con.setRequestMethod("POST");
|
||||
+ con.setInstanceFollowRedirects(false);
|
||||
+
|
||||
+ OutputStream request = new GZIPOutputStream(con.getOutputStream()) {{
|
||||
+ this.def.setLevel(7);
|
||||
+ }};
|
||||
+
|
||||
+ request.write(JSONValue.toJSONString(out).getBytes("UTF-8"));
|
||||
+ request.close();
|
||||
+
|
||||
+ response = getResponse(con);
|
||||
+
|
||||
+ if (con.getResponseCode() != 302) {
|
||||
+ listeners.sendMessage(
|
||||
+ ChatColor.RED + "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage());
|
||||
+ listeners.sendMessage(ChatColor.RED + "Check your logs for more information");
|
||||
+ if (response != null) {
|
||||
+ Bukkit.getLogger().log(Level.SEVERE, response);
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ timingsURL = con.getHeaderField("Location");
|
||||
+ listeners.sendMessage(ChatColor.GREEN + "View Timings Report: " + timingsURL);
|
||||
+
|
||||
+ if (response != null && !response.isEmpty()) {
|
||||
+ Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response);
|
||||
+ }
|
||||
+ } catch (IOException ex) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
|
||||
+ if (response != null) {
|
||||
+ Bukkit.getLogger().log(Level.SEVERE, response);
|
||||
+ }
|
||||
+ Bukkit.getLogger().log(Level.SEVERE, "Could not paste timings", ex);
|
||||
+ } finally {
|
||||
+ this.listeners.done(timingsURL);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private String getResponse(HttpURLConnection con) throws IOException {
|
||||
+ InputStream is = null;
|
||||
+ try {
|
||||
+ is = con.getInputStream();
|
||||
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
+
|
||||
+ byte[] b = new byte[1024];
|
||||
+ int bytesRead;
|
||||
+ while ((bytesRead = is.read(b)) != -1) {
|
||||
+ bos.write(b, 0, bytesRead);
|
||||
+ }
|
||||
+ return bos.toString();
|
||||
+
|
||||
+ } catch (IOException ex) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
|
||||
+ Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex);
|
||||
+ return null;
|
||||
+ } finally {
|
||||
+ if (is != null) {
|
||||
+ is.close();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/co/aikar/timings/TimingsManager.java b/src/main/java/co/aikar/timings/TimingsManager.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ef824d701c97cad8b31e76ad98c94fc4367a7eda
|
||||
@ -3182,10 +2821,18 @@ index f6fb72fab398ae8ca8b746154ff3c8fcad378faf..fad4e929264e2be534d3c4a90a5d557f
|
||||
* Sends the component to the player
|
||||
*
|
||||
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
index 247d194f86c00db11acbc58e7d163b2606db4f07..72c5501e8503aa3b5564a0467fde270d7cd93492 100644
|
||||
index 247d194f86c00db11acbc58e7d163b2606db4f07..26dbc2a761108d6aad056a786cb5146c63b7ad3d 100644
|
||||
--- a/src/main/java/org/bukkit/UnsafeValues.java
|
||||
+++ b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
@@ -69,4 +69,12 @@ public interface UnsafeValues {
|
||||
@@ -18,6 +18,7 @@ import org.bukkit.plugin.PluginDescriptionFile;
|
||||
@Deprecated
|
||||
public interface UnsafeValues {
|
||||
|
||||
+ void reportTimings(); // Paper
|
||||
Material toLegacy(Material material);
|
||||
|
||||
Material fromLegacy(Material material);
|
||||
@@ -69,4 +70,12 @@ public interface UnsafeValues {
|
||||
* @return true if a file matching this key was found and deleted
|
||||
*/
|
||||
boolean removeAdvancement(NamespacedKey key);
|
||||
|
@ -55,10 +55,10 @@ index 0000000000000000000000000000000000000000..2a2651299e8dc631938ba4b4078dc694
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
index 72c5501e8503aa3b5564a0467fde270d7cd93492..c0ff133dece238297bbdf4cb938c9a3070783ec4 100644
|
||||
index 26dbc2a761108d6aad056a786cb5146c63b7ad3d..98df287bcb1462fa42b7d4a706a68d36927fbc1c 100644
|
||||
--- a/src/main/java/org/bukkit/UnsafeValues.java
|
||||
+++ b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
@@ -76,5 +76,12 @@ public interface UnsafeValues {
|
||||
@@ -77,5 +77,12 @@ public interface UnsafeValues {
|
||||
* @return name
|
||||
*/
|
||||
String getTimingsServerName();
|
||||
|
@ -7,10 +7,10 @@ Not here to name and shame, only so server admins can be aware of which
|
||||
plugins have and haven't been updated.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
index c0ff133dece238297bbdf4cb938c9a3070783ec4..821064264405cde147e944df279b44a20a4868ad 100644
|
||||
index 98df287bcb1462fa42b7d4a706a68d36927fbc1c..6f5601639c472db62120bab8d903620ee87f7e5c 100644
|
||||
--- a/src/main/java/org/bukkit/UnsafeValues.java
|
||||
+++ b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
@@ -83,5 +83,11 @@ public interface UnsafeValues {
|
||||
@@ -84,5 +84,11 @@ public interface UnsafeValues {
|
||||
default com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
|
||||
return new com.destroystokyo.paper.util.VersionFetcher.DummyVersionFetcher();
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ Subject: [PATCH] Add Raw Byte ItemStack Serialization
|
||||
Serializes using NBT which is safer for server data migrations than bukkits format.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
index 821064264405cde147e944df279b44a20a4868ad..4fa00140cf17e3ea7d602b6337b3fe4f2901202e 100644
|
||||
index 6f5601639c472db62120bab8d903620ee87f7e5c..70d95e89a050632b2b0e2f477d3c286a3e8db1bd 100644
|
||||
--- a/src/main/java/org/bukkit/UnsafeValues.java
|
||||
+++ b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
@@ -89,5 +89,9 @@ public interface UnsafeValues {
|
||||
@@ -90,5 +90,9 @@ public interface UnsafeValues {
|
||||
static boolean isLegacyPlugin(org.bukkit.plugin.Plugin plugin) {
|
||||
return !Bukkit.getUnsafe().isSupportedApiVersion(plugin.getDescription().getAPIVersion());
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ Subject: [PATCH] Timings v2
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/MinecraftTimings.java b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..223d3b1125d0781758c45c6b469e6cccd13f187a
|
||||
index 0000000000000000000000000000000000000000..33342139a042ebec5fb4e8566028f8f7e3149937
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/co/aikar/timings/MinecraftTimings.java
|
||||
@@ -0,0 +1,141 @@
|
||||
@@ -0,0 +1,145 @@
|
||||
+package co.aikar.timings;
|
||||
+
|
||||
+import com.google.common.collect.MapMaker;
|
||||
@ -81,9 +81,13 @@ index 0000000000000000000000000000000000000000..223d3b1125d0781758c45c6b469e6ccc
|
||||
+
|
||||
+ final String taskname = taskNameCache.computeIfAbsent(taskClass, clazz -> {
|
||||
+ try {
|
||||
+ return clazz.isAnonymousClass() || clazz.isLocalClass()
|
||||
+ String clsName = clazz.isAnonymousClass() || clazz.isLocalClass()
|
||||
+ ? clazz.getName()
|
||||
+ : clazz.getCanonicalName();
|
||||
+ if (clsName.contains("$Lambda$")) {
|
||||
+ clsName = clsName.replaceAll("(Lambda\\$.*?)/.*", "$1");
|
||||
+ }
|
||||
+ return clsName;
|
||||
+ } catch (Throwable ex) {
|
||||
+ new Exception("Error occurred detecting class name", ex).printStackTrace();
|
||||
+ return "MangledClassFile";
|
||||
@ -151,6 +155,389 @@ index 0000000000000000000000000000000000000000..223d3b1125d0781758c45c6b469e6ccc
|
||||
+ return Timings.ofSafe("Command Function - " + function.getMinecraftKey().toString());
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d4ebcf8f66197299256bd6b65710a1488c90ea41
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
@@ -0,0 +1,377 @@
|
||||
+/*
|
||||
+ * This file is licensed under the MIT License (MIT).
|
||||
+ *
|
||||
+ * Copyright (c) 2014 Daniel Ennis <http://aikar.co>
|
||||
+ *
|
||||
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
+ * of this software and associated documentation files (the "Software"), to deal
|
||||
+ * in the Software without restriction, including without limitation the rights
|
||||
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
+ * copies of the Software, and to permit persons to whom the Software is
|
||||
+ * furnished to do so, subject to the following conditions:
|
||||
+ *
|
||||
+ * The above copyright notice and this permission notice shall be included in
|
||||
+ * all copies or substantial portions of the Software.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
+ * THE SOFTWARE.
|
||||
+ */
|
||||
+package co.aikar.timings;
|
||||
+
|
||||
+import com.google.common.collect.Sets;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import org.apache.commons.lang.StringUtils;
|
||||
+import org.bukkit.Bukkit;
|
||||
+import org.bukkit.ChatColor;
|
||||
+import org.bukkit.Material;
|
||||
+import org.bukkit.configuration.ConfigurationSection;
|
||||
+import org.bukkit.configuration.MemorySection;
|
||||
+import org.bukkit.craftbukkit.util.CraftChatMessage;
|
||||
+import org.bukkit.entity.EntityType;
|
||||
+import org.json.simple.JSONObject;
|
||||
+import org.json.simple.JSONValue;
|
||||
+
|
||||
+import java.io.ByteArrayOutputStream;
|
||||
+import java.io.IOException;
|
||||
+import java.io.InputStream;
|
||||
+import java.io.OutputStream;
|
||||
+import java.lang.management.ManagementFactory;
|
||||
+import java.lang.management.OperatingSystemMXBean;
|
||||
+import java.lang.management.RuntimeMXBean;
|
||||
+import java.net.HttpURLConnection;
|
||||
+import java.net.InetAddress;
|
||||
+import java.net.URL;
|
||||
+import java.util.List;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+import java.util.logging.Level;
|
||||
+import java.util.zip.GZIPOutputStream;
|
||||
+
|
||||
+import static co.aikar.timings.TimingsManager.HISTORY;
|
||||
+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"})
|
||||
+public class TimingsExport extends Thread {
|
||||
+
|
||||
+ private final TimingsReportListener listeners;
|
||||
+ private final Map out;
|
||||
+ private final TimingHistory[] history;
|
||||
+ private static long lastReport = 0;
|
||||
+
|
||||
+ private TimingsExport(TimingsReportListener listeners, Map out, TimingHistory[] history) {
|
||||
+ super("Timings paste thread");
|
||||
+ this.listeners = listeners;
|
||||
+ this.out = out;
|
||||
+ this.history = history;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Checks if any pending reports are being requested, and builds one if needed.
|
||||
+ */
|
||||
+ public static void reportTimings() {
|
||||
+ if (Timings.requestingReport.isEmpty()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ TimingsReportListener listeners = new TimingsReportListener(Timings.requestingReport);
|
||||
+ listeners.addConsoleIfNeeded();
|
||||
+
|
||||
+ Timings.requestingReport.clear();
|
||||
+ long now = System.currentTimeMillis();
|
||||
+ final long lastReportDiff = now - lastReport;
|
||||
+ if (lastReportDiff < 60000) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Please wait at least 1 minute in between Timings reports. (" + (int)((60000 - lastReportDiff) / 1000) + " seconds)");
|
||||
+ listeners.done();
|
||||
+ return;
|
||||
+ }
|
||||
+ final long lastStartDiff = now - TimingsManager.timingStart;
|
||||
+ if (lastStartDiff < 180000) {
|
||||
+ 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;
|
||||
+ }
|
||||
+ listeners.sendMessage(ChatColor.GREEN + "Preparing Timings Report...");
|
||||
+ lastReport = now;
|
||||
+ Map parent = createObject(
|
||||
+ // Get some basic system details about the server
|
||||
+ pair("version", Bukkit.getVersion()),
|
||||
+ pair("maxplayers", Bukkit.getMaxPlayers()),
|
||||
+ pair("start", TimingsManager.timingStart / 1000),
|
||||
+ pair("end", System.currentTimeMillis() / 1000),
|
||||
+ pair("online-mode", Bukkit.getServer().getOnlineMode()),
|
||||
+ pair("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000),
|
||||
+ pair("datapacks", toArrayMapper(MinecraftServer.getServer().getResourcePackRepository().d(), pack -> {
|
||||
+ // Don't feel like obf helper'ing these, non fatal if its temp missed.
|
||||
+ return ChatColor.stripColor(CraftChatMessage.fromComponent(pack.a(true)));
|
||||
+ }))
|
||||
+ );
|
||||
+ if (!TimingsManager.privacy) {
|
||||
+ appendObjectData(parent,
|
||||
+ pair("server", Bukkit.getUnsafe().getTimingsServerName()),
|
||||
+ pair("motd", Bukkit.getServer().getMotd()),
|
||||
+ pair("icon", Bukkit.getServer().getServerIcon().getData())
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ final Runtime runtime = Runtime.getRuntime();
|
||||
+ RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
|
||||
+
|
||||
+ OperatingSystemMXBean osInfo = ManagementFactory.getOperatingSystemMXBean();
|
||||
+
|
||||
+ parent.put("system", createObject(
|
||||
+ pair("timingcost", getCost()),
|
||||
+ pair("loadavg", osInfo.getSystemLoadAverage()),
|
||||
+ pair("name", System.getProperty("os.name")),
|
||||
+ pair("version", System.getProperty("os.version")),
|
||||
+ pair("jvmversion", System.getProperty("java.version")),
|
||||
+ pair("arch", System.getProperty("os.arch")),
|
||||
+ pair("maxmem", runtime.maxMemory()),
|
||||
+ pair("memory", createObject(
|
||||
+ pair("heap", ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().toString()),
|
||||
+ pair("nonheap", ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().toString()),
|
||||
+ pair("finalizing", ManagementFactory.getMemoryMXBean().getObjectPendingFinalizationCount())
|
||||
+ )),
|
||||
+ pair("cpu", runtime.availableProcessors()),
|
||||
+ pair("runtime", runtimeBean.getUptime()),
|
||||
+ pair("flags", StringUtils.join(runtimeBean.getInputArguments(), " ")),
|
||||
+ pair("gc", toObjectMapper(ManagementFactory.getGarbageCollectorMXBeans(), input -> pair(input.getName(), toArray(input.getCollectionCount(), input.getCollectionTime()))))
|
||||
+ )
|
||||
+ );
|
||||
+
|
||||
+ parent.put("worlds", toObjectMapper(MinecraftServer.getServer().getWorlds(), world -> {
|
||||
+ if (world.getWorldData().getName().equals("worldeditregentempworld")) return null;
|
||||
+ return pair(world.getWorldData().getName(), createObject(
|
||||
+ pair("gamerules", toObjectMapper(world.getWorld().getGameRules(), rule -> {
|
||||
+ return pair(rule, world.getWorld().getGameRuleValue(rule));
|
||||
+ })),
|
||||
+ pair("ticking-distance", world.getChunkProvider().playerChunkMap.getEffectiveViewDistance())
|
||||
+ ));
|
||||
+ }));
|
||||
+
|
||||
+ Set<Material> tileEntityTypeSet = Sets.newHashSet();
|
||||
+ Set<EntityType> entityTypeSet = Sets.newHashSet();
|
||||
+
|
||||
+ int size = HISTORY.size();
|
||||
+ TimingHistory[] history = new TimingHistory[size + 1];
|
||||
+ int i = 0;
|
||||
+ for (TimingHistory timingHistory : HISTORY) {
|
||||
+ tileEntityTypeSet.addAll(timingHistory.tileEntityTypeSet);
|
||||
+ entityTypeSet.addAll(timingHistory.entityTypeSet);
|
||||
+ history[i++] = timingHistory;
|
||||
+ }
|
||||
+
|
||||
+ history[i] = new TimingHistory(); // Current snapshot
|
||||
+ tileEntityTypeSet.addAll(history[i].tileEntityTypeSet);
|
||||
+ entityTypeSet.addAll(history[i].entityTypeSet);
|
||||
+
|
||||
+
|
||||
+ Map handlers = createObject();
|
||||
+ Map groupData;
|
||||
+ synchronized (TimingIdentifier.GROUP_MAP) {
|
||||
+ for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) {
|
||||
+ synchronized (group.handlers) {
|
||||
+ for (TimingHandler id : group.handlers) {
|
||||
+
|
||||
+ if (!id.isTimed() && !id.isSpecial()) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ String name = id.identifier.name;
|
||||
+ if (name.startsWith("##")) {
|
||||
+ name = name.substring(3);
|
||||
+ }
|
||||
+ handlers.put(id.id, toArray(
|
||||
+ group.id,
|
||||
+ name
|
||||
+ ));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ groupData = toObjectMapper(
|
||||
+ TimingIdentifier.GROUP_MAP.values(), group -> pair(group.id, group.name));
|
||||
+ }
|
||||
+
|
||||
+ parent.put("idmap", createObject(
|
||||
+ pair("groups", groupData),
|
||||
+ pair("handlers", handlers),
|
||||
+ pair("worlds", toObjectMapper(TimingHistory.worldMap.entrySet(), input -> pair(input.getValue(), input.getKey()))),
|
||||
+ pair("tileentity",
|
||||
+ toObjectMapper(tileEntityTypeSet, input -> pair(input.ordinal(), input.name()))),
|
||||
+ pair("entity",
|
||||
+ toObjectMapper(entityTypeSet, input -> pair(input.ordinal(), input.name())))
|
||||
+ ));
|
||||
+
|
||||
+ // Information about loaded plugins
|
||||
+
|
||||
+ parent.put("plugins", toObjectMapper(Bukkit.getPluginManager().getPlugins(),
|
||||
+ plugin -> pair(plugin.getName(), createObject(
|
||||
+ pair("version", plugin.getDescription().getVersion()),
|
||||
+ pair("description", String.valueOf(plugin.getDescription().getDescription()).trim()),
|
||||
+ pair("website", plugin.getDescription().getWebsite()),
|
||||
+ pair("authors", StringUtils.join(plugin.getDescription().getAuthors(), ", "))
|
||||
+ ))));
|
||||
+
|
||||
+
|
||||
+
|
||||
+ // Information on the users Config
|
||||
+
|
||||
+ parent.put("config", createObject(
|
||||
+ pair("spigot", mapAsJSON(Bukkit.spigot().getSpigotConfig(), null)),
|
||||
+ pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)),
|
||||
+ pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null))
|
||||
+ ));
|
||||
+
|
||||
+ new TimingsExport(listeners, parent, history).start();
|
||||
+ }
|
||||
+
|
||||
+ static long getCost() {
|
||||
+ // Benchmark the users System.nanotime() for cost basis
|
||||
+ int passes = 100;
|
||||
+ TimingHandler SAMPLER1 = Timings.ofSafe("Timings Sampler 1");
|
||||
+ TimingHandler SAMPLER2 = Timings.ofSafe("Timings Sampler 2");
|
||||
+ TimingHandler SAMPLER3 = Timings.ofSafe("Timings Sampler 3");
|
||||
+ TimingHandler SAMPLER4 = Timings.ofSafe("Timings Sampler 4");
|
||||
+ TimingHandler SAMPLER5 = Timings.ofSafe("Timings Sampler 5");
|
||||
+ TimingHandler SAMPLER6 = Timings.ofSafe("Timings Sampler 6");
|
||||
+
|
||||
+ long start = System.nanoTime();
|
||||
+ for (int i = 0; i < passes; i++) {
|
||||
+ SAMPLER1.startTiming();
|
||||
+ SAMPLER2.startTiming();
|
||||
+ SAMPLER3.startTiming();
|
||||
+ SAMPLER3.stopTiming();
|
||||
+ SAMPLER4.startTiming();
|
||||
+ SAMPLER5.startTiming();
|
||||
+ SAMPLER6.startTiming();
|
||||
+ SAMPLER6.stopTiming();
|
||||
+ SAMPLER5.stopTiming();
|
||||
+ SAMPLER4.stopTiming();
|
||||
+ SAMPLER2.stopTiming();
|
||||
+ SAMPLER1.stopTiming();
|
||||
+ }
|
||||
+ long timingsCost = (System.nanoTime() - start) / passes / 6;
|
||||
+ SAMPLER1.reset(true);
|
||||
+ SAMPLER2.reset(true);
|
||||
+ SAMPLER3.reset(true);
|
||||
+ SAMPLER4.reset(true);
|
||||
+ SAMPLER5.reset(true);
|
||||
+ SAMPLER6.reset(true);
|
||||
+ return timingsCost;
|
||||
+ }
|
||||
+
|
||||
+ private static JSONObject mapAsJSON(ConfigurationSection config, String parentKey) {
|
||||
+
|
||||
+ JSONObject object = new JSONObject();
|
||||
+ for (String key : config.getKeys(false)) {
|
||||
+ String fullKey = (parentKey != null ? parentKey + "." + key : key);
|
||||
+ if (fullKey.equals("database") || fullKey.equals("settings.bungeecord-addresses") || TimingsManager.hiddenConfigs.contains(fullKey) || key.startsWith("seed-") || key.equals("worldeditregentempworld")) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ final Object val = config.get(key);
|
||||
+
|
||||
+ object.put(key, valAsJSON(val, fullKey));
|
||||
+ }
|
||||
+ return object;
|
||||
+ }
|
||||
+
|
||||
+ private static Object valAsJSON(Object val, final String parentKey) {
|
||||
+ if (!(val instanceof MemorySection)) {
|
||||
+ if (val instanceof List) {
|
||||
+ Iterable<Object> v = (Iterable<Object>) val;
|
||||
+ return toArrayMapper(v, input -> valAsJSON(input, parentKey));
|
||||
+ } else {
|
||||
+ return String.valueOf(val);
|
||||
+ }
|
||||
+ } else {
|
||||
+ return mapAsJSON((ConfigurationSection) val, parentKey);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void run() {
|
||||
+ out.put("data", toArrayMapper(history, TimingHistory::export));
|
||||
+
|
||||
+
|
||||
+ String response = null;
|
||||
+ String timingsURL = null;
|
||||
+ try {
|
||||
+ HttpURLConnection con = (HttpURLConnection) new URL("http://timings.aikar.co/post").openConnection();
|
||||
+ con.setDoOutput(true);
|
||||
+ String hostName = "BrokenHost";
|
||||
+ try {
|
||||
+ hostName = InetAddress.getLocalHost().getHostName();
|
||||
+ } catch (Exception ignored) {}
|
||||
+ con.setRequestProperty("User-Agent", "Paper/" + Bukkit.getUnsafe().getTimingsServerName() + "/" + hostName);
|
||||
+ con.setRequestMethod("POST");
|
||||
+ con.setInstanceFollowRedirects(false);
|
||||
+
|
||||
+ OutputStream request = new GZIPOutputStream(con.getOutputStream()) {{
|
||||
+ this.def.setLevel(7);
|
||||
+ }};
|
||||
+
|
||||
+ request.write(JSONValue.toJSONString(out).getBytes("UTF-8"));
|
||||
+ request.close();
|
||||
+
|
||||
+ response = getResponse(con);
|
||||
+
|
||||
+ if (con.getResponseCode() != 302) {
|
||||
+ listeners.sendMessage(
|
||||
+ ChatColor.RED + "Upload Error: " + con.getResponseCode() + ": " + con.getResponseMessage());
|
||||
+ listeners.sendMessage(ChatColor.RED + "Check your logs for more information");
|
||||
+ if (response != null) {
|
||||
+ Bukkit.getLogger().log(Level.SEVERE, response);
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ timingsURL = con.getHeaderField("Location");
|
||||
+ listeners.sendMessage(ChatColor.GREEN + "View Timings Report: " + timingsURL);
|
||||
+
|
||||
+ if (response != null && !response.isEmpty()) {
|
||||
+ Bukkit.getLogger().log(Level.INFO, "Timing Response: " + response);
|
||||
+ }
|
||||
+ } catch (IOException ex) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
|
||||
+ if (response != null) {
|
||||
+ Bukkit.getLogger().log(Level.SEVERE, response);
|
||||
+ }
|
||||
+ Bukkit.getLogger().log(Level.SEVERE, "Could not paste timings", ex);
|
||||
+ } finally {
|
||||
+ this.listeners.done(timingsURL);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private String getResponse(HttpURLConnection con) throws IOException {
|
||||
+ InputStream is = null;
|
||||
+ try {
|
||||
+ is = con.getInputStream();
|
||||
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
+
|
||||
+ byte[] b = new byte[1024];
|
||||
+ int bytesRead;
|
||||
+ while ((bytesRead = is.read(b)) != -1) {
|
||||
+ bos.write(b, 0, bytesRead);
|
||||
+ }
|
||||
+ return bos.toString();
|
||||
+
|
||||
+ } catch (IOException ex) {
|
||||
+ listeners.sendMessage(ChatColor.RED + "Error uploading timings, check your logs for more information");
|
||||
+ Bukkit.getLogger().log(Level.WARNING, con.getResponseMessage(), ex);
|
||||
+ return null;
|
||||
+ } finally {
|
||||
+ if (is != null) {
|
||||
+ is.close();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/co/aikar/timings/WorldTimingsHandler.java b/src/main/java/co/aikar/timings/WorldTimingsHandler.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..fa1c920ea6092259149f9e7f9cd7cc1ed27bf338
|
||||
@ -1204,7 +1591,7 @@ index 820180ab3f7053c348caa80cc21f15dfa3d26afd..fa6400dccd4df635d696e0858c0c164a
|
||||
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
|
||||
public CraftPersistentDataContainer persistentDataContainer;
|
||||
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
|
||||
index d9ff52eda71fcdf88d4c9114450237bcba2ccb08..740c59004514a332ebe556c4e91f84bd9bf4a11d 100644
|
||||
index 45ded8cd3aee69083f6196765208d8c2430f0a02..a126a6d22ccee90d0aadb8513bda60455a703bf6 100644
|
||||
--- a/src/main/java/net/minecraft/server/World.java
|
||||
+++ b/src/main/java/net/minecraft/server/World.java
|
||||
@@ -1,5 +1,7 @@
|
||||
@ -1791,10 +2178,23 @@ index e52ef47b783785dc214746b678e7b549aea9a274..3d90b3426873a3528af14f7f1ab0adae
|
||||
this.value = value;
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index 68728b4d86c4037fb1907bd16d86df5e23e8fe77..02f33005335a0995ce4157088353da93833b6ecc 100644
|
||||
index 68728b4d86c4037fb1907bd16d86df5e23e8fe77..f647450b8c6977b4a6bb1819b34052c4ae2fe0f4 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -298,6 +298,13 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
@@ -133,6 +133,12 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
return CraftNamespacedKey.toMinecraft(mat.getKey());
|
||||
}
|
||||
// ========================================================================
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void reportTimings() {
|
||||
+ co.aikar.timings.TimingsExport.reportTimings();
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public static byte toLegacyData(IBlockData data) {
|
||||
return CraftLegacy.toLegacyData(data);
|
||||
@@ -298,6 +304,13 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
|
@ -126,10 +126,10 @@ index 0000000000000000000000000000000000000000..5deed3e25ff41ab0a4015a5fd0c1e952
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index 02f33005335a0995ce4157088353da93833b6ecc..b1e1b59d451674b42cdc6f896d3e2b707a03b923 100644
|
||||
index f647450b8c6977b4a6bb1819b34052c4ae2fe0f4..79ddf03c7f3afc868cb73ee4c000fc879ede90d8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -303,6 +303,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
@@ -309,6 +309,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
public String getTimingsServerName() {
|
||||
return com.destroystokyo.paper.PaperConfig.timingsServerName;
|
||||
}
|
||||
|
@ -5,10 +5,10 @@ Subject: [PATCH] Add CraftMagicNumbers.isSupportedApiVersion()
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index b1e1b59d451674b42cdc6f896d3e2b707a03b923..770375ed4207920e71d2d0799c611c4b3cdbe6f7 100644
|
||||
index 79ddf03c7f3afc868cb73ee4c000fc879ede90d8..6363074c38312387b62e6cf5df2592aefb078f29 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -308,6 +308,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
@@ -314,6 +314,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
|
||||
return new com.destroystokyo.paper.PaperVersionFetcher();
|
||||
}
|
||||
|
@ -50,10 +50,10 @@ index 2322c0c8c5aacebb6317eab8ce4245554f6d9d55..3e6f878cdbbf5ebfa7fb390745ead135
|
||||
DataOutputStream dataoutputstream = new DataOutputStream(new BufferedOutputStream(new GZIPOutputStream(outputstream)));
|
||||
Throwable throwable = null;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index 770375ed4207920e71d2d0799c611c4b3cdbe6f7..b58f2ef5ce5f3047bf8fcfc8d80a4aa9774ff711 100644
|
||||
index 6363074c38312387b62e6cf5df2592aefb078f29..004b6ce132f8a686116b2a03a0a57461c8e164cf 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -313,6 +313,46 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
@@ -319,6 +319,46 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
public boolean isSupportedApiVersion(String apiVersion) {
|
||||
return apiVersion != null && SUPPORTED_API.contains(apiVersion);
|
||||
}
|
||||
|
@ -8,6 +8,20 @@ Implements world view distance getters/setters
|
||||
Per-Player is absent due to difficulty of maintaining
|
||||
the diff required to make it happen.
|
||||
|
||||
diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
index d4ebcf8f66197299256bd6b65710a1488c90ea41..a3b41ce5fc70948d4804659a472cb622bb9bbc07 100644
|
||||
--- a/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
+++ b/src/main/java/co/aikar/timings/TimingsExport.java
|
||||
@@ -153,7 +153,8 @@ public class TimingsExport extends Thread {
|
||||
pair("gamerules", toObjectMapper(world.getWorld().getGameRules(), rule -> {
|
||||
return pair(rule, world.getWorld().getGameRuleValue(rule));
|
||||
})),
|
||||
- pair("ticking-distance", world.getChunkProvider().playerChunkMap.getEffectiveViewDistance())
|
||||
+ pair("ticking-distance", world.getChunkProvider().playerChunkMap.getEffectiveViewDistance()),
|
||||
+ pair("notick-viewdistance", world.getChunkProvider().playerChunkMap.getEffectiveNoTickViewDistance())
|
||||
));
|
||||
}));
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 4612697569fd6e3683b0e58453b61a9a8d077229..5c8a946d5c895fc2622c7df656cc462c58104cf7 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@ -539,7 +553,7 @@ index 74b868d7cec0260a10ca7718f48308f4ec54d56b..f832e7cdfc6741a932787f02754f1452
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
|
||||
index 60af90bf8c376ab8ab61b16ae38886149faa88cc..9b726de6daeba42120f3a948fbdcf080d0e72917 100644
|
||||
index 154b9f9a5696eaebb01dd59b7b27de75e95b501d..3061d856d52776ebc2eed6541238c8a760d7c536 100644
|
||||
--- a/src/main/java/net/minecraft/server/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/PlayerList.java
|
||||
@@ -151,7 +151,7 @@ public abstract class PlayerList {
|
||||
@ -570,7 +584,7 @@ index 60af90bf8c376ab8ab61b16ae38886149faa88cc..9b726de6daeba42120f3a948fbdcf080
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
|
||||
index 4dc03c27bba5cd2dd1d6cb2e82087ef834f41d81..e82b8b9a4dbc9a595df7d8e56596a93fde7b687a 100644
|
||||
index 9f4268202653f6f0ebed49cd67ae691a8b18ccd2..5535f98ac0ec1668b162cb652e88a122bcadac0c 100644
|
||||
--- a/src/main/java/net/minecraft/server/World.java
|
||||
+++ b/src/main/java/net/minecraft/server/World.java
|
||||
@@ -444,8 +444,13 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
|
||||
|
Loading…
Reference in New Issue
Block a user