Updated Upstream (Paper)

Upstream has released updates that appears to apply and compile correctly

Paper Changes:
8ce3dd5f [CI-SKIP] Fix Mojang API Brigadier dep - THIS IS NOT A NEW BUILD
00d760a5 Fix build due to spigot changing the build timestamp process
842e040c Updated Upstream (Bukkit/CraftBukkit/Spigot)
c03260a2 Add getter and setter for villager's numberOfRestocksToday (#3231)
fe366fbe null check tracker for entity metadata update - Fixes #3070
fdf41b74 Implement Brigadier Mojang API
e0ea2e0e Entity Activation Range 2.0! Major improvements to restoring behavior
10396d28 Fix Tracking Range mismatch on Vehicle/Passenger checks
This commit is contained in:
William Blake Galbreath
2020-04-28 20:14:57 -05:00
parent c0e748c0c1
commit a2db5eebbe
67 changed files with 269 additions and 999 deletions

View File

@@ -1,43 +1,48 @@
From cc20b9003b0b7dbc01173445f4a2a8ad6a326795 Mon Sep 17 00:00:00 2001
From e008b74695e3e9846fce63c0db40959ec7683784 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <blake.galbreath@gmail.com>
Date: Thu, 9 May 2019 18:09:43 -0500
Subject: [PATCH] Purpur config files
---
.../com/destroystokyo/paper/PaperConfig.java | 2 +
.../net/minecraft/server/DedicatedServer.java | 9 +
src/main/java/net/minecraft/server/World.java | 4 +-
src/main/java/net/pl3x/purpur/Metrics.java | 598 ++++++++++++++++++
.../java/net/pl3x/purpur/PurpurConfig.java | 136 ++++
.../net/pl3x/purpur/PurpurWorldConfig.java | 67 ++
.../pl3x/purpur/command/PurpurCommand.java | 67 ++
.../org/bukkit/craftbukkit/CraftServer.java | 15 +
.../java/org/bukkit/craftbukkit/Main.java | 8 +
9 files changed, 904 insertions(+), 2 deletions(-)
create mode 100644 src/main/java/net/pl3x/purpur/Metrics.java
.../java/com/destroystokyo/paper/Metrics.java | 6 +-
.../net/minecraft/server/DedicatedServer.java | 9 ++
src/main/java/net/minecraft/server/World.java | 2 +
.../java/net/pl3x/purpur/PurpurConfig.java | 130 ++++++++++++++++++
.../net/pl3x/purpur/PurpurWorldConfig.java | 67 +++++++++
.../pl3x/purpur/command/PurpurCommand.java | 67 +++++++++
.../org/bukkit/craftbukkit/CraftServer.java | 15 ++
.../java/org/bukkit/craftbukkit/Main.java | 8 ++
8 files changed, 301 insertions(+), 3 deletions(-)
create mode 100644 src/main/java/net/pl3x/purpur/PurpurConfig.java
create mode 100644 src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
create mode 100644 src/main/java/net/pl3x/purpur/command/PurpurCommand.java
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index 1c4cd36351..cb8bac539d 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -97,10 +97,12 @@ public class PaperConfig {
MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Paper", entry.getValue());
}
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
index e257d6b36..a6cd76fa5 100644
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
@@ -578,7 +578,7 @@ public class Metrics {
boolean logFailedRequests = config.getBoolean("logFailedRequests", false);
// Only start Metrics, if it's enabled in the config
if (config.getBoolean("enabled", true)) {
- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger());
+ Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Purpur
+ /* // Purpur - Replace with our own
if (!metricsStarted) {
Metrics.PaperMetrics.startMetrics();
metricsStarted = true;
}
+ */ // Purpur end
}
metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> {
String minecraftVersion = Bukkit.getVersion();
@@ -587,8 +587,8 @@ public class Metrics {
}));
static void readConfig(Class<?> clazz, Object instance) {
metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size()));
- metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : "offline"));
- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown"));
+ metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (Bukkit.spigot().getSpigotConfig().getBoolean("settings.bungeecord") ? "bungee" : "offline"))); // Purpur
+ metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown")); // Purpur
metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
Map<String, Map<String, Integer>> map = new HashMap<>();
diff --git a/src/main/java/net/minecraft/server/DedicatedServer.java b/src/main/java/net/minecraft/server/DedicatedServer.java
index 1ef7890da5..e614570d33 100644
index e62ca0543..018def64a 100644
--- a/src/main/java/net/minecraft/server/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/DedicatedServer.java
@@ -192,6 +192,15 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
@@ -57,22 +62,18 @@ index 1ef7890da5..e614570d33 100644
// Paper end
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index d554d4cf0f..618f115ca9 100644
index 899c535c4..d0896d944 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -78,10 +78,9 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
public long ticksPerAmbientSpawns;
@@ -85,6 +85,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
public boolean populating;
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
-
+ public final net.pl3x.purpur.PurpurWorldConfig purpurConfig; // Purpur
public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper
public final ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
-
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
public static BlockPosition lastPhysicsProblem; // Spigot
private org.spigotmc.TickLimiter entityLimiter;
@@ -130,6 +129,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
@@ -136,6 +137,7 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
protected World(WorldData worlddata, DimensionManager dimensionmanager, BiFunction<World, WorldProvider, IChunkProvider> bifunction, GameProfilerFiller gameprofilerfiller, boolean flag, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) {
this.spigotConfig = new org.spigotmc.SpigotWorldConfig( worlddata.getName() ); // Spigot
this.paperConfig = new com.destroystokyo.paper.PaperWorldConfig(worlddata.getName(), this.spigotConfig); // Paper
@@ -80,616 +81,12 @@ index d554d4cf0f..618f115ca9 100644
this.chunkPacketBlockController = this.paperConfig.antiXray ? new ChunkPacketBlockControllerAntiXray(this.paperConfig) : ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray
this.generator = gen;
this.world = new CraftWorld((WorldServer) this, gen, env);
diff --git a/src/main/java/net/pl3x/purpur/Metrics.java b/src/main/java/net/pl3x/purpur/Metrics.java
new file mode 100644
index 0000000000..9210afab6d
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/Metrics.java
@@ -0,0 +1,598 @@
+package net.pl3x.purpur;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import javax.net.ssl.HttpsURLConnection;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * bStats collects some data for plugin authors.
+ * <p>
+ * Check out https://bStats.org/ to learn more about bStats!
+ */
+public class Metrics {
+ public static final int B_STATS_VERSION = 1;
+ private static final String URL = "https://bStats.org/submitData/server-implementation";
+ private static boolean logFailedRequests = false;
+ private static Logger logger = Logger.getLogger("bStats");
+ private final String name;
+ private final String serverUUID;
+ private final List<CustomChart> charts = new ArrayList<>();
+
+ /**
+ * Class constructor.
+ *
+ * @param name The name of the server software.
+ * @param serverUUID The uuid of the server.
+ * @param logFailedRequests Whether failed requests should be logged or not.
+ * @param logger The logger for the failed requests.
+ */
+ public Metrics(String name, String serverUUID, boolean logFailedRequests, Logger logger) {
+ this.name = name;
+ this.serverUUID = serverUUID;
+ Metrics.logFailedRequests = logFailedRequests;
+ Metrics.logger = logger;
+
+ startSubmitting();
+ }
+
+ /**
+ * Adds a custom chart.
+ *
+ * @param chart The chart to add.
+ */
+ public void addCustomChart(CustomChart chart) {
+ if (chart == null) {
+ throw new IllegalArgumentException("Chart cannot be null!");
+ }
+ charts.add(chart);
+ }
+
+ /**
+ * Starts the Scheduler which submits our data every 30 minutes.
+ */
+ private void startSubmitting() {
+ final Timer timer = new Timer(true);
+ timer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ submitData();
+ }
+ }, 1000 * 60 * 5, 1000 * 60 * 30);
+ // Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
+ // WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
+ // WARNING: Just don't do it!
+ }
+
+ /**
+ * Gets the plugin specific data.
+ * This method is called using Reflection.
+ *
+ * @return The plugin specific data.
+ */
+ public JsonObject getPluginData() {
+ JsonObject data = new JsonObject();
+
+ data.addProperty("pluginName", name); // Append the name of the plugin
+
+ JsonArray customCharts = new JsonArray();
+ for (CustomChart customChart : charts) {
+ JsonObject chart = customChart.getRequestJsonObject();
+ if (chart != null) {
+ customCharts.add(chart);
+ }
+ }
+ data.add("customCharts", customCharts);
+
+ return data;
+ }
+
+ /**
+ * Gets the server specific data.
+ *
+ * @return The server specific data.
+ */
+ private JsonObject getServerData() {
+ JsonObject data = new JsonObject();
+
+ data.addProperty("serverUUID", serverUUID);
+
+ data.addProperty("osName", System.getProperty("os.name"));
+ data.addProperty("osArch", System.getProperty("os.arch"));
+ data.addProperty("osVersion", System.getProperty("os.version"));
+ data.addProperty("coreCount", Runtime.getRuntime().availableProcessors());
+
+ return data;
+ }
+
+ /**
+ * Collects the data and sends it afterwards.
+ */
+ private void submitData() {
+ final JsonObject data = getServerData();
+
+ JsonArray pluginData = new JsonArray();
+ pluginData.add(getPluginData());
+ data.add("plugins", pluginData);
+
+ try {
+ sendData(data);
+ } catch (Exception e) {
+ if (logFailedRequests) {
+ logger.log(Level.WARNING, "Could not submit plugin stats of " + name, e);
+ }
+ }
+ }
+
+ /**
+ * Sends the data to the bStats server.
+ *
+ * @param data The data to send.
+ * @throws Exception If the request failed.
+ */
+ private static void sendData(JsonObject data) throws Exception {
+ if (data == null) {
+ throw new IllegalArgumentException("Data cannot be null!");
+ }
+ HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
+
+ // Compress the data to save bandwidth
+ byte[] compressedData = compress(data.toString());
+
+ // Add headers
+ connection.setRequestMethod("POST");
+ connection.addRequestProperty("Accept", "application/json");
+ connection.addRequestProperty("Connection", "close");
+ connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
+ connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
+ connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
+ connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
+
+ // Send data
+ connection.setDoOutput(true);
+ DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
+ outputStream.write(compressedData);
+ outputStream.flush();
+ outputStream.close();
+
+ connection.getInputStream().close();
+ }
+
+ /**
+ * Gzips the given String.
+ *
+ * @param str The string to gzip.
+ * @return The gzipped String.
+ * @throws IOException If the compression failed.
+ */
+ private static byte[] compress(final String str) throws IOException {
+ if (str == null) {
+ return null;
+ }
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
+ gzip.write(str.getBytes(StandardCharsets.UTF_8));
+ gzip.close();
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * Represents a custom chart.
+ */
+ public static abstract class CustomChart {
+
+ // The id of the chart
+ final String chartId;
+
+ /**
+ * Class constructor.
+ *
+ * @param chartId The id of the chart.
+ */
+ CustomChart(String chartId) {
+ if (chartId == null || chartId.isEmpty()) {
+ throw new IllegalArgumentException("ChartId cannot be null or empty!");
+ }
+ this.chartId = chartId;
+ }
+
+ private JsonObject getRequestJsonObject() {
+ JsonObject chart = new JsonObject();
+ chart.addProperty("chartId", chartId);
+ try {
+ JsonObject data = getChartData();
+ if (data == null) {
+ // If the data is null we don't send the chart.
+ return null;
+ }
+ chart.add("data", data);
+ } catch (Throwable t) {
+ if (logFailedRequests) {
+ Bukkit.getLogger().log(Level.WARNING, "Failed to get data for custom chart with id " + chartId, t);
+ }
+ return null;
+ }
+ return chart;
+ }
+
+ protected abstract JsonObject getChartData() throws Exception;
+
+ }
+
+ /**
+ * Represents a custom simple pie.
+ */
+ public static class SimplePie extends CustomChart {
+
+ private final Callable<String> callable;
+
+ /**
+ * Class constructor.
+ *
+ * @param chartId The id of the chart.
+ * @param callable The callable which is used to request the chart data.
+ */
+ public SimplePie(String chartId, Callable<String> callable) {
+ super(chartId);
+ this.callable = callable;
+ }
+
+ @Override
+ protected JsonObject getChartData() throws Exception {
+ JsonObject data = new JsonObject();
+ String value = callable.call();
+ if (value == null || value.isEmpty()) {
+ // Null = skip the chart
+ return null;
+ }
+ data.addProperty("value", value);
+ return data;
+ }
+ }
+
+ /**
+ * Represents a custom advanced pie.
+ */
+ public static class AdvancedPie extends CustomChart {
+
+ private final Callable<Map<String, Integer>> callable;
+
+ /**
+ * Class constructor.
+ *
+ * @param chartId The id of the chart.
+ * @param callable The callable which is used to request the chart data.
+ */
+ public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
+ super(chartId);
+ this.callable = callable;
+ }
+
+ @Override
+ protected JsonObject getChartData() throws Exception {
+ JsonObject data = new JsonObject();
+ JsonObject values = new JsonObject();
+ Map<String, Integer> map = callable.call();
+ if (map == null || map.isEmpty()) {
+ // Null = skip the chart
+ return null;
+ }
+ boolean allSkipped = true;
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
+ if (entry.getValue() == 0) {
+ continue; // Skip this invalid
+ }
+ allSkipped = false;
+ values.addProperty(entry.getKey(), entry.getValue());
+ }
+ if (allSkipped) {
+ // Null = skip the chart
+ return null;
+ }
+ data.add("values", values);
+ return data;
+ }
+ }
+
+ /**
+ * Represents a custom drilldown pie.
+ */
+ public static class DrilldownPie extends CustomChart {
+
+ private final Callable<Map<String, Map<String, Integer>>> callable;
+
+ /**
+ * Class constructor.
+ *
+ * @param chartId The id of the chart.
+ * @param callable The callable which is used to request the chart data.
+ */
+ public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
+ super(chartId);
+ this.callable = callable;
+ }
+
+ @Override
+ public JsonObject getChartData() throws Exception {
+ JsonObject data = new JsonObject();
+ JsonObject values = new JsonObject();
+ Map<String, Map<String, Integer>> map = callable.call();
+ if (map == null || map.isEmpty()) {
+ // Null = skip the chart
+ return null;
+ }
+ boolean reallyAllSkipped = true;
+ for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
+ JsonObject value = new JsonObject();
+ boolean allSkipped = true;
+ for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
+ value.addProperty(valueEntry.getKey(), valueEntry.getValue());
+ allSkipped = false;
+ }
+ if (!allSkipped) {
+ reallyAllSkipped = false;
+ values.add(entryValues.getKey(), value);
+ }
+ }
+ if (reallyAllSkipped) {
+ // Null = skip the chart
+ return null;
+ }
+ data.add("values", values);
+ return data;
+ }
+ }
+
+ /**
+ * Represents a custom single line chart.
+ */
+ public static class SingleLineChart extends CustomChart {
+
+ private final Callable<Integer> callable;
+
+ /**
+ * Class constructor.
+ *
+ * @param chartId The id of the chart.
+ * @param callable The callable which is used to request the chart data.
+ */
+ public SingleLineChart(String chartId, Callable<Integer> callable) {
+ super(chartId);
+ this.callable = callable;
+ }
+
+ @Override
+ protected JsonObject getChartData() throws Exception {
+ JsonObject data = new JsonObject();
+ int value = callable.call();
+ if (value == 0) {
+ // Null = skip the chart
+ return null;
+ }
+ data.addProperty("value", value);
+ return data;
+ }
+
+ }
+
+ /**
+ * Represents a custom multi line chart.
+ */
+ public static class MultiLineChart extends CustomChart {
+
+ private final Callable<Map<String, Integer>> callable;
+
+ /**
+ * Class constructor.
+ *
+ * @param chartId The id of the chart.
+ * @param callable The callable which is used to request the chart data.
+ */
+ public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
+ super(chartId);
+ this.callable = callable;
+ }
+
+ @Override
+ protected JsonObject getChartData() throws Exception {
+ JsonObject data = new JsonObject();
+ JsonObject values = new JsonObject();
+ Map<String, Integer> map = callable.call();
+ if (map == null || map.isEmpty()) {
+ // Null = skip the chart
+ return null;
+ }
+ boolean allSkipped = true;
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
+ if (entry.getValue() == 0) {
+ continue; // Skip this invalid
+ }
+ allSkipped = false;
+ values.addProperty(entry.getKey(), entry.getValue());
+ }
+ if (allSkipped) {
+ // Null = skip the chart
+ return null;
+ }
+ data.add("values", values);
+ return data;
+ }
+
+ }
+
+ /**
+ * Represents a custom simple bar chart.
+ */
+ public static class SimpleBarChart extends CustomChart {
+
+ private final Callable<Map<String, Integer>> callable;
+
+ /**
+ * Class constructor.
+ *
+ * @param chartId The id of the chart.
+ * @param callable The callable which is used to request the chart data.
+ */
+ public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
+ super(chartId);
+ this.callable = callable;
+ }
+
+ @Override
+ protected JsonObject getChartData() throws Exception {
+ JsonObject data = new JsonObject();
+ JsonObject values = new JsonObject();
+ Map<String, Integer> map = callable.call();
+ if (map == null || map.isEmpty()) {
+ // Null = skip the chart
+ return null;
+ }
+ for (Map.Entry<String, Integer> entry : map.entrySet()) {
+ JsonArray categoryValues = new JsonArray();
+ categoryValues.add(entry.getValue());
+ values.add(entry.getKey(), categoryValues);
+ }
+ data.add("values", values);
+ return data;
+ }
+
+ }
+
+ /**
+ * Represents a custom advanced bar chart.
+ */
+ public static class AdvancedBarChart extends CustomChart {
+
+ private final Callable<Map<String, int[]>> callable;
+
+ /**
+ * Class constructor.
+ *
+ * @param chartId The id of the chart.
+ * @param callable The callable which is used to request the chart data.
+ */
+ public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
+ super(chartId);
+ this.callable = callable;
+ }
+
+ @Override
+ protected JsonObject getChartData() throws Exception {
+ JsonObject data = new JsonObject();
+ JsonObject values = new JsonObject();
+ Map<String, int[]> map = callable.call();
+ if (map == null || map.isEmpty()) {
+ // Null = skip the chart
+ return null;
+ }
+ boolean allSkipped = true;
+ for (Map.Entry<String, int[]> entry : map.entrySet()) {
+ if (entry.getValue().length == 0) {
+ continue; // Skip this invalid
+ }
+ allSkipped = false;
+ JsonArray categoryValues = new JsonArray();
+ for (int categoryValue : entry.getValue()) {
+ categoryValues.add(categoryValue);
+ }
+ values.add(entry.getKey(), categoryValues);
+ }
+ if (allSkipped) {
+ // Null = skip the chart
+ return null;
+ }
+ data.add("values", values);
+ return data;
+ }
+ }
+
+ static class PurpurMetrics {
+ static void startMetrics() {
+ File configFile = new File(new File((File) MinecraftServer.getServer().options.valueOf("plugins"), "bStats"), "config.yml");
+ YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
+ if (!config.isSet("serverUuid")) {
+ config.addDefault("enabled", true);
+ config.addDefault("serverUuid", UUID.randomUUID().toString());
+ config.addDefault("logFailedRequests", false);
+ config.options().header(
+ "bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
+ "To honor their work, you should not disable it.\n" +
+ "This has nearly no effect on the server performance!\n" +
+ "Check out https://bStats.org/ to learn more :)"
+ ).copyDefaults(true);
+ try {
+ config.save(configFile);
+ } catch (IOException ignored) {
+ }
+ }
+ String serverUUID = config.getString("serverUuid");
+ boolean logFailedRequests = config.getBoolean("logFailedRequests", false);
+ if (config.getBoolean("enabled", true)) {
+ Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger());
+
+ metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> {
+ String minecraftVersion = Bukkit.getVersion();
+ minecraftVersion = minecraftVersion.substring(minecraftVersion.indexOf("MC: ") + 4, minecraftVersion.length() - 1);
+ return minecraftVersion;
+ }));
+
+ metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size()));
+ metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (Bukkit.spigot().getSpigotConfig().getBoolean("settings.bungeecord") ? "bungee" : "offline")));
+ metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown"));
+
+ metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
+ Map<String, Map<String, Integer>> map = new HashMap<>();
+ String javaVersion = System.getProperty("java.version");
+ Map<String, Integer> entry = new HashMap<>();
+ entry.put(javaVersion, 1);
+
+ // http://openjdk.java.net/jeps/223
+ // Java decided to change their versioning scheme and in doing so modified the java.version system
+ // property to return $major[.$minor][.$secuity][-ea], as opposed to 1.$major.0_$identifier
+ // we can handle pre-9 by checking if the "major" is equal to "1", otherwise, 9+
+ String majorVersion = javaVersion.split("\\.")[0];
+ String release;
+
+ int indexOf = javaVersion.lastIndexOf('.');
+
+ if (majorVersion.equals("1")) {
+ release = "Java " + javaVersion.substring(0, indexOf);
+ } else {
+ // of course, it really wouldn't be all that simple if they didn't add a quirk, now would it
+ // valid strings for the major may potentially include values such as -ea to deannotate a pre release
+ Matcher versionMatcher = Pattern.compile("\\d+").matcher(majorVersion);
+ if (versionMatcher.find()) {
+ majorVersion = versionMatcher.group(0);
+ }
+ release = "Java " + majorVersion;
+ }
+ map.put(release, entry);
+
+ return map;
+ }));
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/pl3x/purpur/PurpurConfig.java b/src/main/java/net/pl3x/purpur/PurpurConfig.java
new file mode 100644
index 0000000000..83466b5837
index 000000000..333c880bf
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/PurpurConfig.java
@@ -0,0 +1,136 @@
@@ -0,0 +1,130 @@
+package net.pl3x.purpur;
+
+import com.google.common.base.Throwables;
@@ -724,7 +121,6 @@ index 0000000000..83466b5837
+ public static YamlConfiguration config;
+
+ private static Map<String, Command> commands;
+ private static boolean metricsStarted;
+
+ static int version;
+ static boolean verbose;
@@ -766,11 +162,6 @@ index 0000000000..83466b5837
+ for (Map.Entry<String, Command> entry : commands.entrySet()) {
+ MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Purpur", entry.getValue());
+ }
+
+ if (!metricsStarted) {
+ Metrics.PurpurMetrics.startMetrics();
+ metricsStarted = true;
+ }
+ }
+
+ static void readConfig(Class<?> clazz, Object instance) {
@@ -828,7 +219,7 @@ index 0000000000..83466b5837
+}
diff --git a/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
new file mode 100644
index 0000000000..eda37fa43f
index 000000000..eda37fa43
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/PurpurWorldConfig.java
@@ -0,0 +1,67 @@
@@ -901,7 +292,7 @@ index 0000000000..eda37fa43f
+}
diff --git a/src/main/java/net/pl3x/purpur/command/PurpurCommand.java b/src/main/java/net/pl3x/purpur/command/PurpurCommand.java
new file mode 100644
index 0000000000..7d983d9a54
index 000000000..7d983d9a5
--- /dev/null
+++ b/src/main/java/net/pl3x/purpur/command/PurpurCommand.java
@@ -0,0 +1,67 @@
@@ -973,10 +364,10 @@ index 0000000000..7d983d9a54
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 76fbbb620c..aa084a56b2 100644
index d98011b6e..0d0058c94 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -806,6 +806,7 @@ public final class CraftServer implements Server {
@@ -807,6 +807,7 @@ public final class CraftServer implements Server {
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper
@@ -984,7 +375,7 @@ index 76fbbb620c..aa084a56b2 100644
for (WorldServer world : console.getWorlds()) {
world.worldData.setDifficulty(config.difficulty);
world.setSpawnFlags(config.spawnMonsters, config.spawnAnimals);
@@ -834,6 +835,7 @@ public final class CraftServer implements Server {
@@ -835,6 +836,7 @@ public final class CraftServer implements Server {
}
world.spigotConfig.init(); // Spigot
world.paperConfig.init(); // Paper
@@ -992,7 +383,7 @@ index 76fbbb620c..aa084a56b2 100644
}
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
@@ -852,6 +854,7 @@ public final class CraftServer implements Server {
@@ -853,6 +855,7 @@ public final class CraftServer implements Server {
reloadData();
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper
@@ -1000,7 +391,7 @@ index 76fbbb620c..aa084a56b2 100644
overrideAllCommandBlockCommands = commandsConfiguration.getStringList("command-block-overrides").contains("*");
ignoreVanillaPermissions = commandsConfiguration.getBoolean("ignore-vanilla-permissions");
@@ -2092,6 +2095,18 @@ public final class CraftServer implements Server {
@@ -2093,6 +2096,18 @@ public final class CraftServer implements Server {
return com.destroystokyo.paper.PaperConfig.config;
}
@@ -1020,7 +411,7 @@ index 76fbbb620c..aa084a56b2 100644
public void restart() {
org.spigotmc.RestartCommand.restart();
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index cb60310e63..fc2c313901 100644
index 093dbeae2..e05bfa352 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -138,6 +138,14 @@ public class Main {