More patches

This commit is contained in:
Nassim Jahnke 2022-06-07 21:15:06 +02:00
parent a9c507310b
commit 2710efc693
No known key found for this signature in database
GPG key ID: 6BE3B555EBC5982B
56 changed files with 324 additions and 397 deletions

View file

@ -1,301 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Mon, 29 Feb 2016 21:02:09 -0600
Subject: [PATCH] Paper command
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c7738412ce5c9b8c66e3f1c1e13fcd2a2154195
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
@@ -0,0 +1,289 @@
+package com.destroystokyo.paper;
+
+import com.google.common.base.Functions;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerChunkCache;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.EntityType;
+import net.minecraft.world.level.ChunkPos;
+import org.apache.commons.lang3.tuple.MutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.entity.Player;
+
+import java.io.File;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static net.kyori.adventure.text.Component.text;
+import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
+import static net.kyori.adventure.text.format.NamedTextColor.RED;
+import static net.kyori.adventure.text.format.NamedTextColor.YELLOW;
+
+public class PaperCommand extends Command {
+ private static final String BASE_PERM = "bukkit.command.paper.";
+ private static final ImmutableSet<String> SUBCOMMANDS = ImmutableSet.<String>builder().add("heap", "entity", "reload", "version").build();
+
+ public PaperCommand(String name) {
+ super(name);
+ this.description = "Paper related commands";
+ this.usageMessage = "/paper [" + Joiner.on(" | ").join(SUBCOMMANDS) + "]";
+ this.setPermission("bukkit.command.paper;" + Joiner.on(';').join(SUBCOMMANDS.stream().map(s -> BASE_PERM + s).collect(Collectors.toSet())));
+ }
+
+ private static boolean testPermission(CommandSender commandSender, String permission) {
+ if (commandSender.hasPermission(BASE_PERM + permission) || commandSender.hasPermission("bukkit.command.paper")) return true;
+ commandSender.sendMessage(text("I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.", RED));
+ return false;
+ }
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
+ if (args.length <= 1)
+ return getListMatchingLast(sender, args, SUBCOMMANDS);
+
+ switch (args[0].toLowerCase(Locale.ENGLISH))
+ {
+ case "entity":
+ if (args.length == 2)
+ return getListMatchingLast(sender, args, "help", "list");
+ if (args.length == 3)
+ return getListMatchingLast(sender, args, EntityType.getEntityNameList().stream().map(ResourceLocation::toString).sorted().toArray(String[]::new));
+ break;
+ }
+ return Collections.emptyList();
+ }
+
+ // Code from Mojang - copyright them
+ public static List<String> getListMatchingLast(CommandSender sender, String[] args, String... matches) {
+ return getListMatchingLast(sender, args, (Collection) Arrays.asList(matches));
+ }
+
+ public static boolean matches(String s, String s1) {
+ return s1.regionMatches(true, 0, s, 0, s.length());
+ }
+
+ public static List<String> getListMatchingLast(CommandSender sender, String[] strings, Collection<?> collection) {
+ String last = strings[strings.length - 1];
+ ArrayList<String> results = Lists.newArrayList();
+
+ if (!collection.isEmpty()) {
+ Iterator iterator = Iterables.transform(collection, Functions.toStringFunction()).iterator();
+
+ while (iterator.hasNext()) {
+ String s1 = (String) iterator.next();
+
+ if (matches(last, s1) && (sender.hasPermission(BASE_PERM + s1) || sender.hasPermission("bukkit.command.paper"))) {
+ results.add(s1);
+ }
+ }
+
+ if (results.isEmpty()) {
+ iterator = collection.iterator();
+
+ while (iterator.hasNext()) {
+ Object object = iterator.next();
+
+ if (object instanceof ResourceLocation && matches(last, ((ResourceLocation) object).getPath())) {
+ results.add(String.valueOf(object));
+ }
+ }
+ }
+ }
+
+ return results;
+ }
+ // end copy stuff
+
+ @Override
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
+ if (!testPermission(sender)) return true;
+
+ if (args.length == 0) {
+ sender.sendMessage(text("Usage: " + this.usageMessage, RED));
+ return false;
+ }
+ if (SUBCOMMANDS.contains(args[0].toLowerCase(Locale.ENGLISH))) {
+ if (!testPermission(sender, args[0].toLowerCase(Locale.ENGLISH))) return true;
+ }
+ switch (args[0].toLowerCase(Locale.ENGLISH)) {
+ case "heap":
+ dumpHeap(sender);
+ break;
+ case "entity":
+ listEntities(sender, args);
+ break;
+ case "reload":
+ doReload(sender);
+ break;
+ case "ver":
+ if (!testPermission(sender, "version")) break; // "ver" needs a special check because it's an alias. All other commands are checked up before the switch statement (because they are present in the SUBCOMMANDS set)
+ case "version":
+ Command ver = MinecraftServer.getServer().server.getCommandMap().getCommand("version");
+ if (ver != null) {
+ ver.execute(sender, commandLabel, new String[0]);
+ break;
+ }
+ // else - fall through to default
+ default:
+ sender.sendMessage(text("Usage: " + this.usageMessage, RED));
+ return false;
+ }
+
+ return true;
+ }
+
+ /*
+ * Ported from MinecraftForge - author: LexManos <LexManos@gmail.com> - License: LGPLv2.1
+ */
+ private void listEntities(CommandSender sender, String[] args) {
+ if (args.length < 2 || args[1].toLowerCase(Locale.ENGLISH).equals("help")) {
+ sender.sendMessage(text("Use /paper entity [list] help for more information on a specific command", RED));
+ return;
+ }
+
+ switch (args[1].toLowerCase(Locale.ENGLISH)) {
+ case "list":
+ String filter = "*";
+ if (args.length > 2) {
+ if (args[2].toLowerCase(Locale.ENGLISH).equals("help")) {
+ sender.sendMessage(text("Use /paper entity list [filter] [worldName] to get entity info that matches the optional filter.", RED));
+ return;
+ }
+ filter = args[2];
+ }
+ final String cleanfilter = filter.replace("?", ".?").replace("*", ".*?");
+ Set<ResourceLocation> names = EntityType.getEntityNameList().stream()
+ .filter(n -> n.toString().matches(cleanfilter))
+ .collect(Collectors.toSet());
+
+ if (names.isEmpty()) {
+ sender.sendMessage(text("Invalid filter, does not match any entities. Use /paper entity list for a proper list", RED));
+ sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED));
+ return;
+ }
+
+ String worldName;
+ if (args.length > 3) {
+ worldName = args[3];
+ } else if (sender instanceof Player) {
+ worldName = ((Player) sender).getWorld().getName();
+ } else {
+ sender.sendMessage(text("Please specify the name of a world", RED));
+ sender.sendMessage(text("To do so without a filter, specify '*' as the filter", RED));
+ sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED));
+ return;
+ }
+
+ Map<ResourceLocation, MutablePair<Integer, Map<ChunkPos, Integer>>> list = Maps.newHashMap();
+ World bukkitWorld = Bukkit.getWorld(worldName);
+ if (bukkitWorld == null) {
+ sender.sendMessage(text("Could not load world for " + worldName + ". Please select a valid world.", RED));
+ sender.sendMessage(text("Usage: /paper entity list [filter] [worldName]", RED));
+ return;
+ }
+ ServerLevel world = ((CraftWorld) Bukkit.getWorld(worldName)).getHandle();
+
+ Map<ResourceLocation, Integer> nonEntityTicking = Maps.newHashMap();
+ ServerChunkCache chunkProviderServer = world.getChunkSource();
+
+ world.getAllEntities().forEach(e -> {
+ ResourceLocation key = EntityType.getKey(e.getType());
+
+ MutablePair<Integer, Map<ChunkPos, Integer>> info = list.computeIfAbsent(key, k -> MutablePair.of(0, Maps.newHashMap()));
+ ChunkPos chunk = e.chunkPosition();
+ info.left++;
+ info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1);
+ if (!chunkProviderServer.isPositionTicking(e)) {
+ nonEntityTicking.merge(key, Integer.valueOf(1), Integer::sum);
+ }
+ });
+
+ if (names.size() == 1) {
+ ResourceLocation name = names.iterator().next();
+ Pair<Integer, Map<ChunkPos, Integer>> info = list.get(name);
+ int nonTicking = nonEntityTicking.getOrDefault(name, Integer.valueOf(0)).intValue();
+ if (info == null) {
+ sender.sendMessage(text("No entities found.", RED));
+ return;
+ }
+ sender.sendMessage("Entity: " + name + " Total Ticking: " + (info.getLeft() - nonTicking) + ", Total Non-Ticking: " + nonTicking);
+ info.getRight().entrySet().stream()
+ .sorted((a, b) -> !a.getValue().equals(b.getValue()) ? b.getValue() - a.getValue() : a.getKey().toString().compareTo(b.getKey().toString()))
+ .limit(10).forEach(e -> sender.sendMessage(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isPositionTicking(e.getKey().toLong()) ? " (Ticking)" : " (Non-Ticking)")));
+ } else {
+ List<Pair<ResourceLocation, Integer>> info = list.entrySet().stream()
+ .filter(e -> names.contains(e.getKey()))
+ .map(e -> Pair.of(e.getKey(), e.getValue().left))
+ .sorted((a, b) -> !a.getRight().equals(b.getRight()) ? b.getRight() - a.getRight() : a.getKey().toString().compareTo(b.getKey().toString()))
+ .collect(Collectors.toList());
+
+ if (info == null || info.size() == 0) {
+ sender.sendMessage(text("No entities found.", RED));
+ return;
+ }
+
+ int count = info.stream().mapToInt(Pair::getRight).sum();
+ int nonTickingCount = nonEntityTicking.values().stream().mapToInt(Integer::intValue).sum();
+ sender.sendMessage("Total Ticking: " + (count - nonTickingCount) + ", Total Non-Ticking: " + nonTickingCount);
+ info.forEach(e -> {
+ int nonTicking = nonEntityTicking.getOrDefault(e.getKey(), Integer.valueOf(0)).intValue();
+ sender.sendMessage(" " + (e.getValue() - nonTicking) + " (" + nonTicking + ") " + ": " + e.getKey());
+ });
+ sender.sendMessage("* First number is ticking entities, second number is non-ticking entities");
+ }
+ break;
+ }
+ }
+
+ private void dumpHeap(CommandSender sender) {
+ java.nio.file.Path dir = java.nio.file.Paths.get("./dumps");
+ String name = "heap-dump-" + DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now());
+
+ Command.broadcastCommandMessage(sender, text("Writing JVM heap data...", YELLOW));
+
+ java.nio.file.Path file = CraftServer.dumpHeap(dir, name);
+ if (file != null) {
+ Command.broadcastCommandMessage(sender, text("Heap dump saved to " + file, GREEN));
+ } else {
+ Command.broadcastCommandMessage(sender, text("Failed to write heap dump, see server log for details", RED));
+ }
+ }
+
+ private void doReload(CommandSender sender) {
+ Command.broadcastCommandMessage(sender, text("Please note that this command is not supported and may cause issues.", RED));
+ Command.broadcastCommandMessage(sender, text("If you encounter any issues please use the /stop command to restart your server.", RED));
+
+ MinecraftServer console = MinecraftServer.getServer();
+ com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings"));
+ for (ServerLevel world : console.getAllLevels()) {
+ world.paperConfig.init();
+ }
+ console.server.reloadCount++;
+
+ Command.broadcastCommandMessage(sender, text("Paper config reload complete.", GREEN));
+ }
+}

View file

@ -1,67 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sun, 3 Mar 2019 20:53:18 -0800
Subject: [PATCH] Not implemeneted
Currently a placeholder patch.
diff --git a/src/main/java/io/papermc/paper/util/TickThread.java b/src/main/java/io/papermc/paper/util/TickThread.java
new file mode 100644
index 0000000000000000000000000000000000000000..c92f7e59f490f7b289325d9cc2bf7c2cf1750c7a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/TickThread.java
@@ -0,0 +1,41 @@
+package io.papermc.paper.util;
+
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.Bukkit;
+
+public final class TickThread extends Thread {
+
+ public static final boolean STRICT_THREAD_CHECKS = Boolean.getBoolean("paper.strict-thread-checks");
+
+ static {
+ if (STRICT_THREAD_CHECKS) {
+ MinecraftServer.LOGGER.warn("Strict thread checks enabled - performance may suffer");
+ }
+ }
+
+ public static void softEnsureTickThread(final String reason) {
+ if (!STRICT_THREAD_CHECKS) {
+ return;
+ }
+ ensureTickThread(reason);
+ }
+
+
+ public static void ensureTickThread(final String reason) {
+ if (!Bukkit.isPrimaryThread()) {
+ MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
+ throw new IllegalStateException(reason);
+ }
+ }
+
+ public final int id; /* We don't override getId as the spec requires that it be unique (with respect to all other threads) */
+
+ public TickThread(final Runnable run, final String name, final int id) {
+ super(run, name);
+ this.id = id;
+ }
+
+ public static TickThread getCurrentTickThread() {
+ return (TickThread)Thread.currentThread();
+ }
+}
diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java
index bbf0d9d9c44fe8d7add2f978994ec129420814c7..78669fa035b7537ff7e533cf32aaf2995625424f 100644
--- a/src/main/java/org/spigotmc/AsyncCatcher.java
+++ b/src/main/java/org/spigotmc/AsyncCatcher.java
@@ -9,7 +9,7 @@ public class AsyncCatcher
public static void catchOp(String reason)
{
- if ( AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread )
+ if ( (AsyncCatcher.enabled || io.papermc.paper.util.TickThread.STRICT_THREAD_CHECKS) && Thread.currentThread() != MinecraftServer.getServer().serverThread ) // Paper
{
throw new IllegalStateException( "Asynchronous " + reason + "!" );
}

View file

@ -1,735 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Fri, 24 Mar 2017 23:56:01 -0500
Subject: [PATCH] Paper Metrics
Removes Spigot's mcstats metrics in favor of a system using bStats
To disable for privacy or other reasons go to the bStats folder in your plugins folder
and edit the config.yml file present there.
Please keep in mind the data collected is anonymous and collection should have no
tangible effect on server performance. The data is used to allow the authors of
PaperMC to track version and platform usage so that we can make better management
decisions on behalf of the project.
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
new file mode 100644
index 0000000000000000000000000000000000000000..e3b74dbdf8e14219a56fab939f3174e0c2f66de6
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
@@ -0,0 +1,670 @@
+package com.destroystokyo.paper;
+
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.craftbukkit.util.CraftMagicNumbers;
+import org.bukkit.plugin.Plugin;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+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.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+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.
+ *
+ * Check out https://bStats.org/ to learn more about bStats!
+ */
+public class Metrics {
+
+ // Executor service for requests
+ // We use an executor service because the Bukkit scheduler is affected by server lags
+ private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+
+ // The version of this bStats class
+ public static final int B_STATS_VERSION = 1;
+
+ // The url to which the data is sent
+ private static final String URL = "https://bStats.org/submitData/server-implementation";
+
+ // Should failed requests be logged?
+ private static boolean logFailedRequests = false;
+
+ // The logger for the failed requests
+ private static Logger logger = Logger.getLogger("bStats");
+
+ // The name of the server software
+ private final String name;
+
+ // The uuid of the server
+ private final String serverUUID;
+
+ // A list with all custom charts
+ 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;
+
+ // Start submitting the data
+ 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 Runnable submitTask = this::submitData;
+
+ // Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution of requests on the
+ // bStats backend. To circumvent this problem, we introduce some randomness into the initial and second delay.
+ // WARNING: You must not modify any part of this Metrics class, including the submit delay or frequency!
+ // WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it!
+ long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
+ long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
+ scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
+ scheduler.scheduleAtFixedRate(submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Gets the plugin specific data.
+ *
+ * @return The plugin specific data.
+ */
+ private JSONObject getPluginData() {
+ JSONObject data = new JSONObject();
+
+ data.put("pluginName", name); // Append the name of the server software
+ JSONArray customCharts = new JSONArray();
+ for (CustomChart customChart : charts) {
+ // Add the data of the custom charts
+ JSONObject chart = customChart.getRequestJsonObject();
+ if (chart == null) { // If the chart is null, we skip it
+ continue;
+ }
+ customCharts.add(chart);
+ }
+ data.put("customCharts", customCharts);
+
+ return data;
+ }
+
+ /**
+ * Gets the server specific data.
+ *
+ * @return The server specific data.
+ */
+ private JSONObject getServerData() {
+ // OS specific data
+ String osName = System.getProperty("os.name");
+ String osArch = System.getProperty("os.arch");
+ String osVersion = System.getProperty("os.version");
+ int coreCount = Runtime.getRuntime().availableProcessors();
+
+ JSONObject data = new JSONObject();
+
+ data.put("serverUUID", serverUUID);
+
+ data.put("osName", osName);
+ data.put("osArch", osArch);
+ data.put("osVersion", osVersion);
+ data.put("coreCount", coreCount);
+
+ return data;
+ }
+
+ /**
+ * Collects the data and sends it afterwards.
+ */
+ private void submitData() {
+ final JSONObject data = getServerData();
+
+ JSONArray pluginData = new JSONArray();
+ pluginData.add(getPluginData());
+ data.put("plugins", pluginData);
+
+ try {
+ // We are still in the Thread of the timer, so nothing get blocked :)
+ sendData(data);
+ } catch (Exception e) {
+ // Something went wrong! :(
+ if (logFailedRequests) {
+ logger.log(Level.WARNING, "Could not submit 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(); // We don't care about the response - Just send our data :)
+ }
+
+ /**
+ * 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("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.put("chartId", chartId);
+ try {
+ JSONObject data = getChartData();
+ if (data == null) {
+ // If the data is null we don't send the chart.
+ return null;
+ }
+ chart.put("data", data);
+ } catch (Throwable t) {
+ if (logFailedRequests) {
+ logger.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.put("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.put(entry.getKey(), entry.getValue());
+ }
+ if (allSkipped) {
+ // Null = skip the chart
+ return null;
+ }
+ data.put("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.put(valueEntry.getKey(), valueEntry.getValue());
+ allSkipped = false;
+ }
+ if (!allSkipped) {
+ reallyAllSkipped = false;
+ values.put(entryValues.getKey(), value);
+ }
+ }
+ if (reallyAllSkipped) {
+ // Null = skip the chart
+ return null;
+ }
+ data.put("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.put("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.put(entry.getKey(), entry.getValue());
+ }
+ if (allSkipped) {
+ // Null = skip the chart
+ return null;
+ }
+ data.put("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.put(entry.getKey(), categoryValues);
+ }
+ data.put("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.put(entry.getKey(), categoryValues);
+ }
+ if (allSkipped) {
+ // Null = skip the chart
+ return null;
+ }
+ data.put("values", values);
+ return data;
+ }
+
+ }
+
+ static class PaperMetrics {
+ static void startMetrics() {
+ // Get the config file
+ File configFile = new File(new File((File) MinecraftServer.getServer().options.valueOf("plugins"), "bStats"), "config.yml");
+ YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
+
+ // Check if the config file exists
+ if (!config.isSet("serverUuid")) {
+
+ // Add default values
+ config.addDefault("enabled", true);
+ // Every server gets it's unique random id.
+ config.addDefault("serverUuid", UUID.randomUUID().toString());
+ // Should failed request be logged?
+ config.addDefault("logFailedRequests", false);
+
+ // Inform the server owners about bStats
+ 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) {
+ }
+ }
+ // Load the data
+ String serverUUID = config.getString("serverUuid");
+ 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.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" : "offline"));
+ metrics.addCustomChart(new Metrics.SimplePie("paper_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;
+ }));
+
+ metrics.addCustomChart(new Metrics.DrilldownPie("legacy_plugins", () -> {
+ Map<String, Map<String, Integer>> map = new HashMap<>();
+
+ // count legacy plugins
+ int legacy = 0;
+ for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
+ if (CraftMagicNumbers.isLegacy(plugin.getDescription())) {
+ legacy++;
+ }
+ }
+
+ // insert real value as lower dimension
+ Map<String, Integer> entry = new HashMap<>();
+ entry.put(String.valueOf(legacy), 1);
+
+ // create buckets as higher dimension
+ if (legacy == 0) {
+ map.put("0 \uD83D\uDE0E", entry); // :sunglasses:
+ } else if (legacy <= 5) {
+ map.put("1-5", entry);
+ } else if (legacy <= 10) {
+ map.put("6-10", entry);
+ } else if (legacy <= 25) {
+ map.put("11-25", entry);
+ } else if (legacy <= 50) {
+ map.put("26-50", entry);
+ } else {
+ map.put("50+ \uD83D\uDE2D", entry); // :cry:
+ }
+
+ return map;
+ }));
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index c1eb4201ecb0541c606ef0d05b828ae9c87c8a2c..52e9dca37dab4cacdded3b084c40d4dd75182bb5 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -42,6 +42,7 @@ public class PaperConfig {
private static boolean verbose;
private static boolean fatalError;
/*========================================================================*/
+ private static boolean metricsStarted;
public static void init(File configFile) {
CONFIG_FILE = configFile;
@@ -84,6 +85,11 @@ public class PaperConfig {
for (Map.Entry<String, Command> entry : commands.entrySet()) {
MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Paper", entry.getValue());
}
+
+ if (!metricsStarted) {
+ Metrics.PaperMetrics.startMetrics();
+ metricsStarted = true;
+ }
}
static void readConfig(Class<?> clazz, Object instance) {
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
index 43aa6b0129892b8ab8ec25c16a131541c6607487..9d3d65de7cb0be25aa7fc40353390280943b55f4 100644
--- a/src/main/java/org/spigotmc/SpigotConfig.java
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
@@ -83,6 +83,7 @@ public class SpigotConfig
MinecraftServer.getServer().server.getCommandMap().register( entry.getKey(), "Spigot", entry.getValue() );
}
+ /* // Paper - Replace with our own
if ( SpigotConfig.metrics == null )
{
try
@@ -94,6 +95,7 @@ public class SpigotConfig
Bukkit.getServer().getLogger().log( Level.SEVERE, "Could not start metrics service", ex );
}
}
+ */ // Paper end
}
static void readConfig(Class<?> clazz, Object instance)

File diff suppressed because it is too large Load diff

View file

@ -1,84 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Tue, 18 May 2021 14:39:44 -0700
Subject: [PATCH] Add command line option to load extra plugin jars not in the
plugins folder
ex: java -jar paperclip.jar nogui -add-plugin=/path/to/plugin.jar -add-plugin=/path/to/another/plugin_jar.jar
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index a40995140db011271bd092b0b7415d1eee0e8b18..a9f3bddd33cf7f7773c262f1b818eed9895987ef 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -399,10 +399,15 @@ public final class CraftServer implements Server {
public void loadPlugins() {
this.pluginManager.registerInterface(JavaPluginLoader.class);
- File pluginFolder = (File) console.options.valueOf("plugins");
+ File pluginFolder = this.getPluginsFolder(); // Paper
- if (pluginFolder.exists()) {
- Plugin[] plugins = this.pluginManager.loadPlugins(pluginFolder);
+ // Paper start
+ if (true || pluginFolder.exists()) {
+ if (!pluginFolder.exists()) {
+ pluginFolder.mkdirs();
+ }
+ Plugin[] plugins = this.pluginManager.loadPlugins(pluginFolder, this.extraPluginJars());
+ // Paper end
for (Plugin plugin : plugins) {
try {
String message = String.format("Loading %s", plugin.getDescription().getFullName());
@@ -417,6 +422,35 @@ public final class CraftServer implements Server {
}
}
+ // Paper start
+ @Override
+ public File getPluginsFolder() {
+ return (File) this.console.options.valueOf("plugins");
+ }
+
+ private List<File> extraPluginJars() {
+ @SuppressWarnings("unchecked")
+ final List<File> jars = (List<File>) this.console.options.valuesOf("add-plugin");
+ final List<File> list = new ArrayList<>();
+ for (final File file : jars) {
+ if (!file.exists()) {
+ net.minecraft.server.MinecraftServer.LOGGER.warn("File '{}' specified through 'add-plugin' argument does not exist, cannot load a plugin from it!", file.getAbsolutePath());
+ continue;
+ }
+ if (!file.isFile()) {
+ net.minecraft.server.MinecraftServer.LOGGER.warn("File '{}' specified through 'add-plugin' argument is not a file, cannot load a plugin from it!", file.getAbsolutePath());
+ continue;
+ }
+ if (!file.getName().endsWith(".jar")) {
+ net.minecraft.server.MinecraftServer.LOGGER.warn("File '{}' specified through 'add-plugin' argument is not a jar file, cannot load a plugin from it!", file.getAbsolutePath());
+ continue;
+ }
+ list.add(file);
+ }
+ return list;
+ }
+ // Paper end
+
public void enablePlugins(PluginLoadOrder type) {
if (type == PluginLoadOrder.STARTUP) {
this.helpMap.clear();
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index aff3116c77277dcb4d3825d33f40a0b17258a0ba..ae4dc96da9e50ce8645e1b5da13e29085e916e98 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -142,6 +142,12 @@ public class Main {
.ofType(File.class)
.defaultsTo(new File("paper.yml"))
.describedAs("Yml file");
+
+ acceptsAll(asList("add-plugin", "add-extra-plugin-jar"), "Specify paths to extra plugin jars to be loaded in addition to those in the plugins folder. This argument can be specified multiple times, once for each extra plugin jar path.")
+ .withRequiredArg()
+ .ofType(File.class)
+ .defaultsTo(new File[] {})
+ .describedAs("Jar file");
// Paper end
}
};

View file

@ -1,113 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 1 Mar 2016 13:02:51 -0600
Subject: [PATCH] Configurable cactus bamboo and reed growth heights
Bamboo - Both the minimum fully-grown heights and the maximum are configurable
- Machine_Maker
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 0853ff7641103447f458b2dc08076c27e3937074..3f7ec17466e4fae7139672854e2c8223ada16b76 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -101,4 +101,16 @@ public class PaperWorldConfig {
config.addDefault("world-settings.default." + path, def.stream().map(Enum::name).collect(Collectors.toList()));
return ((List<String>) (config.getList("world-settings." + worldName + "." + path, config.getList("world-settings.default." + path)))).stream().map(s -> Enum.valueOf(type, s)).collect(Collectors.toList());
}
+
+ public int cactusMaxHeight;
+ public int reedMaxHeight;
+ public int bambooMaxHeight;
+ public int bambooMinHeight;
+ private void blockGrowthHeight() {
+ cactusMaxHeight = getInt("max-growth-height.cactus", 3);
+ reedMaxHeight = getInt("max-growth-height.reeds", 3);
+ bambooMaxHeight = getInt("max-growth-height.bamboo.max", 16);
+ bambooMinHeight = getInt("max-growth-height.bamboo.min", 11);
+ log("Max height for cactus growth " + cactusMaxHeight + ". Max height for reed growth " + reedMaxHeight + ". Max height for bamboo growth " + bambooMaxHeight + ". Min height for fully-grown bamboo " + bambooMinHeight + ".");
+ }
}
diff --git a/src/main/java/net/minecraft/world/level/block/BambooBlock.java b/src/main/java/net/minecraft/world/level/block/BambooBlock.java
index f088f866b8f28d2627e4a60527a1f8dfa243bb47..482d6cd1065df5b0703301d403efb42ca4d5363b 100644
--- a/src/main/java/net/minecraft/world/level/block/BambooBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BambooBlock.java
@@ -135,7 +135,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
if (random.nextInt(Math.max(1, (int) (100.0F / world.spigotConfig.bambooModifier) * 3)) == 0 && world.isEmptyBlock(pos.above()) && world.getRawBrightness(pos.above(), 0) >= 9) { // Spigot
int i = this.getHeightBelowUpToMax(world, pos) + 1;
- if (i < 16) {
+ if (i < world.paperConfig.bambooMaxHeight) { // Paper
this.growBamboo(state, world, pos, random, i);
}
}
@@ -166,7 +166,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
int i = this.getHeightAboveUpToMax(world, pos);
int j = this.getHeightBelowUpToMax(world, pos);
- return i + j + 1 < 16 && (Integer) world.getBlockState(pos.above(i)).getValue(BambooBlock.STAGE) != 1;
+ return i + j + 1 < ((Level) world).paperConfig.bambooMaxHeight && (Integer) world.getBlockState(pos.above(i)).getValue(BambooBlock.STAGE) != 1; // Paper
}
@Override
@@ -185,7 +185,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
BlockPos blockposition1 = pos.above(i);
BlockState iblockdata1 = world.getBlockState(blockposition1);
- if (k >= 16 || !iblockdata1.is(Blocks.BAMBOO) || (Integer) iblockdata1.getValue(BambooBlock.STAGE) == 1 || !world.isEmptyBlock(blockposition1.above())) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here
+ if (k >= world.paperConfig.bambooMaxHeight || !iblockdata1.is(Blocks.BAMBOO) || (Integer) iblockdata1.getValue(BambooBlock.STAGE) == 1 || !world.isEmptyBlock(blockposition1.above())) { // CraftBukkit - If the BlockSpreadEvent was cancelled, we have no bamboo here // Paper - Configurable cactus bamboo and reed growth heights
return;
}
@@ -226,7 +226,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
}
int j = (Integer) state.getValue(BambooBlock.AGE) != 1 && !iblockdata2.is(Blocks.BAMBOO) ? 0 : 1;
- int k = (height < 11 || random.nextFloat() >= 0.25F) && height != 15 ? 0 : 1;
+ int k = (height < world.paperConfig.bambooMinHeight || random.nextFloat() >= 0.25F) && height != (world.paperConfig.bambooMaxHeight - 1) ? 0 : 1; // Paper
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockSpreadEvent(world, pos, pos.above(), (BlockState) ((BlockState) ((BlockState) this.defaultBlockState().setValue(BambooBlock.AGE, j)).setValue(BambooBlock.LEAVES, blockpropertybamboosize)).setValue(BambooBlock.STAGE, k), 3)) {
@@ -241,7 +241,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
protected int getHeightAboveUpToMax(BlockGetter world, BlockPos pos) {
int i;
- for (i = 0; i < 16 && world.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO); ++i) {
+ for (i = 0; i < ((Level) world).paperConfig.bambooMaxHeight && world.getBlockState(pos.above(i + 1)).is(Blocks.BAMBOO); ++i) { // Paper
;
}
@@ -251,7 +251,7 @@ public class BambooBlock extends Block implements BonemealableBlock {
protected int getHeightBelowUpToMax(BlockGetter world, BlockPos pos) {
int i;
- for (i = 0; i < 16 && world.getBlockState(pos.below(i + 1)).is(Blocks.BAMBOO); ++i) {
+ for (i = 0; i < ((Level) world).paperConfig.bambooMaxHeight && world.getBlockState(pos.below(i + 1)).is(Blocks.BAMBOO); ++i) { // Paper
;
}
diff --git a/src/main/java/net/minecraft/world/level/block/CactusBlock.java b/src/main/java/net/minecraft/world/level/block/CactusBlock.java
index b6b769fb354187cb31f878b87cce63049c0c7cf8..f1bbfc85582d29a50a82f9207509985dcb76b693 100644
--- a/src/main/java/net/minecraft/world/level/block/CactusBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CactusBlock.java
@@ -55,7 +55,7 @@ public class CactusBlock extends Block {
;
}
- if (i < 3) {
+ if (i < world.paperConfig.cactusMaxHeight) { // Paper - Configurable growth height
int j = (Integer) state.getValue(CactusBlock.AGE);
if (j >= (byte) range(3, ((100.0F / world.spigotConfig.cactusModifier) * 15) + 0.5F, 15)) { // Spigot
diff --git a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
index d40492e9729f165ed944ab2c9fa81cde042ce49c..66c06e0f7c8d223a2b00bab57a15e3a705fe176a 100644
--- a/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SugarCaneBlock.java
@@ -52,7 +52,7 @@ public class SugarCaneBlock extends Block {
;
}
- if (i < 3) {
+ if (i < world.paperConfig.reedMaxHeight) { // Paper - Configurable growth height
int j = (Integer) state.getValue(SugarCaneBlock.AGE);
if (j >= (byte) range(3, ((100.0F / world.spigotConfig.caneModifier) * 15) + 0.5F, 15)) { // Spigot

View file

@ -1,51 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 1 Mar 2016 13:09:16 -0600
Subject: [PATCH] Configurable baby zombie movement speed
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 3f7ec17466e4fae7139672854e2c8223ada16b76..4d787f0596be1a44724ade309cc00e115778a797 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -113,4 +113,15 @@ public class PaperWorldConfig {
bambooMinHeight = getInt("max-growth-height.bamboo.min", 11);
log("Max height for cactus growth " + cactusMaxHeight + ". Max height for reed growth " + reedMaxHeight + ". Max height for bamboo growth " + bambooMaxHeight + ". Min height for fully-grown bamboo " + bambooMinHeight + ".");
}
+
+ public double babyZombieMovementModifier;
+ private void babyZombieMovementModifier() {
+ babyZombieMovementModifier = getDouble("baby-zombie-movement-modifier", 0.5D);
+ if (PaperConfig.version < 20) {
+ babyZombieMovementModifier = getDouble("baby-zombie-movement-speed", 0.5D);
+ set("baby-zombie-movement-modifier", babyZombieMovementModifier);
+ }
+
+ log("Baby zombies will move at the speed of " + babyZombieMovementModifier);
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
index 627aeb45342c2804f911572056a63aa1cb0110e7..953f138b6cd48cc94bc23a4321a9684b4214637e 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
@@ -76,7 +76,7 @@ import org.bukkit.event.entity.EntityTransformEvent;
public class Zombie extends Monster {
private static final UUID SPEED_MODIFIER_BABY_UUID = UUID.fromString("B9766B59-9566-4402-BC1F-2EE2A276D836");
- private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5D, AttributeModifier.Operation.MULTIPLY_BASE);
+ private final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_UUID, "Baby speed boost", 0.5D, AttributeModifier.Operation.MULTIPLY_BASE); private final AttributeModifier babyModifier = this.SPEED_MODIFIER_BABY; // Paper - remove static - Make baby speed configurable
private static final EntityDataAccessor<Boolean> DATA_BABY_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Integer> DATA_SPECIAL_TYPE_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.INT);
public static final EntityDataAccessor<Boolean> DATA_DROWNED_CONVERSION_ID = SynchedEntityData.defineId(Zombie.class, EntityDataSerializers.BOOLEAN);
@@ -184,9 +184,9 @@ public class Zombie extends Monster {
if (this.level != null && !this.level.isClientSide) {
AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
- attributemodifiable.removeModifier(Zombie.SPEED_MODIFIER_BABY);
+ attributemodifiable.removeModifier(this.babyModifier); // Paper
if (baby) {
- attributemodifiable.addTransientModifier(Zombie.SPEED_MODIFIER_BABY);
+ attributemodifiable.addTransientModifier(this.babyModifier); // Paper
}
}

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 1 Mar 2016 13:14:11 -0600
Subject: [PATCH] Configurable fishing time ranges
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 4d787f0596be1a44724ade309cc00e115778a797..4b9122a3e094aa9e0a789f35fb6b0f9a7a53f772 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -124,4 +124,12 @@ public class PaperWorldConfig {
log("Baby zombies will move at the speed of " + babyZombieMovementModifier);
}
+
+ public int fishingMinTicks;
+ public int fishingMaxTicks;
+ private void fishingTickRange() {
+ fishingMinTicks = getInt("fishing-time-range.MinimumTicks", 100);
+ fishingMaxTicks = getInt("fishing-time-range.MaximumTicks", 600);
+ log("Fishing time ranges are between " + fishingMinTicks +" and " + fishingMaxTicks + " ticks");
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
index 1fe9c591fdb1b8c3d457964a6877a91b56470016..34ee9c22ed5bca2406588a4b6a045bbc51c64920 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
@@ -85,6 +85,10 @@ public class FishingHook extends Projectile {
this.noCulling = true;
this.luck = Math.max(0, luckOfTheSeaLevel);
this.lureSpeed = Math.max(0, lureLevel);
+ // Paper start
+ minWaitTime = world.paperConfig.fishingMinTicks;
+ maxWaitTime = world.paperConfig.fishingMaxTicks;
+ // Paper end
}
public FishingHook(EntityType<? extends FishingHook> type, Level world) {
@@ -400,7 +404,7 @@ public class FishingHook extends Projectile {
} else {
// CraftBukkit start - logic to modify fishing wait time
this.timeUntilLured = Mth.nextInt(this.random, this.minWaitTime, this.maxWaitTime);
- this.timeUntilLured -= (this.applyLure) ? this.lureSpeed * 20 * 5 : 0;
+ this.timeUntilLured -= (this.applyLure) ? (this.lureSpeed * 20 * 5 >= this.maxWaitTime ? this.timeUntilLured - 1 : this.lureSpeed * 20 * 5) : 0; // Paper - Fix Lure infinite loop
// CraftBukkit end
}
}

View file

@ -1,75 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 1 Mar 2016 13:24:16 -0600
Subject: [PATCH] Allow nerfed mobs to jump and take water damage
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 4b9122a3e094aa9e0a789f35fb6b0f9a7a53f772..d2ac0123812224181afae8fca96058ddc8cdff1e 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -132,4 +132,9 @@ public class PaperWorldConfig {
fishingMaxTicks = getInt("fishing-time-range.MaximumTicks", 600);
log("Fishing time ranges are between " + fishingMinTicks +" and " + fishingMaxTicks + " ticks");
}
+
+ public boolean nerfedMobsShouldJump;
+ private void nerfedMobsShouldJump() {
+ nerfedMobsShouldJump = getBoolean("spawner-nerfed-mobs-should-jump", false);
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 63cbe322c272761e769abaa1e707e50c0acbfd8d..d778209604c71a0728748dac91a5cb993f4357b7 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1278,6 +1278,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
return this.isInWater() || this.isInRain();
}
+ @Deprecated public final boolean isInWaterOrRainOrBubble() { return isInWaterRainOrBubble(); } // Paper - OBFHELPER
public boolean isInWaterRainOrBubble() {
return this.isInWater() || this.isInRain() || this.isInBubbleColumn();
}
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 625641be06b7afafec59ce19ecd39c54bf840351..28d0be9c3391a636fdc04c2e081ed462ed512c5d 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -105,6 +105,7 @@ public abstract class Mob extends LivingEntity {
private final BodyRotationControl bodyRotationControl;
protected PathNavigation navigation;
public GoalSelector goalSelector;
+ @Nullable public net.minecraft.world.entity.ai.goal.FloatGoal goalFloat; // Paper
public GoalSelector targetSelector;
@Nullable
private LivingEntity target;
@@ -801,7 +802,17 @@ public abstract class Mob extends LivingEntity {
@Override
protected final void serverAiStep() {
++this.noActionTime;
- if (!this.aware) return; // CraftBukkit
+ if (!this.aware) { // Paper start - Allow nerfed mobs to jump, float and take water damage
+ if (goalFloat != null) {
+ if (goalFloat.canUse()) goalFloat.tick();
+ this.getJumpControl().tick();
+ }
+ if (this.isSensitiveToWater() && isInWaterRainOrBubble()) {
+ hurt(DamageSource.DROWN, 1.0F);
+ }
+ return;
+ }
+ // Paper end
this.level.getProfiler().push("sensing");
this.sensing.tick();
this.level.getProfiler().pop();
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/FloatGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/FloatGoal.java
index 01950951ea06e43bedeeede489a112e577617829..0e86eb2595cf9fbf24f789e0e9b4f05929d3164c 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/FloatGoal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/FloatGoal.java
@@ -9,6 +9,7 @@ public class FloatGoal extends Goal {
public FloatGoal(Mob mob) {
this.mob = mob;
+ if (mob.getCommandSenderWorld().paperConfig.nerfedMobsShouldJump) mob.goalFloat = this; // Paper
this.setFlags(EnumSet.of(Goal.Flag.JUMP));
mob.getNavigation().setCanFloat(true);
}

View file

@ -1,87 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Suddenly <suddenly@suddenly.coffee>
Date: Tue, 1 Mar 2016 13:51:54 -0600
Subject: [PATCH] Add configurable despawn distances for living entities
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index d2ac0123812224181afae8fca96058ddc8cdff1e..3afadc8d916714398974d77aa0f1093729e008ca 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -3,6 +3,9 @@ package com.destroystokyo.paper;
import java.util.List;
import java.util.stream.Collectors;
+import it.unimi.dsi.fastutil.objects.Reference2IntMap;
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+import net.minecraft.world.entity.MobCategory;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.spigotmc.SpigotWorldConfig;
@@ -46,6 +49,13 @@ public class PaperWorldConfig {
public void removeOldValues() {
boolean needsSave = false;
+ if (PaperConfig.version < 24) {
+ needsSave = true;
+
+ set("despawn-ranges.soft", null);
+ set("despawn-ranges.hard", null);
+ }
+
if (needsSave) {
saveConfig();
}
@@ -137,4 +147,31 @@ public class PaperWorldConfig {
private void nerfedMobsShouldJump() {
nerfedMobsShouldJump = getBoolean("spawner-nerfed-mobs-should-jump", false);
}
+
+ public final Reference2IntMap<MobCategory> softDespawnDistances = new Reference2IntOpenHashMap<>(MobCategory.values().length);
+ public final Reference2IntMap<MobCategory> hardDespawnDistances = new Reference2IntOpenHashMap<>(MobCategory.values().length);
+ private void despawnDistances() {
+ if (PaperConfig.version < 24) {
+ int softDistance = getInt("despawn-ranges.soft", 32, false); // 32^2 = 1024, Minecraft Default
+ int hardDistance = getInt("despawn-ranges.hard", 128, false); // 128^2 = 16384, Minecraft Default
+ for (MobCategory value : MobCategory.values()) {
+ if (softDistance != 32) {
+ softDespawnDistances.put(value, softDistance);
+ }
+ if (hardDistance != 128) {
+ hardDespawnDistances.put(value, hardDistance);
+ }
+ }
+ }
+ for (MobCategory category : MobCategory.values()) {
+ int softDistance = getInt("despawn-ranges." + category.getName() + ".soft", softDespawnDistances.getOrDefault(category, category.getNoDespawnDistance()));
+ int hardDistance = getInt("despawn-ranges." + category.getName() + ".hard", hardDespawnDistances.getOrDefault(category, category.getDespawnDistance()));
+ if (softDistance > hardDistance) {
+ softDistance = hardDistance;
+ }
+ log("Mobs in " + category.getName() + " Despawn Ranges: Soft" + softDistance + " Hard: " + hardDistance);
+ softDespawnDistances.put(category, softDistance);
+ hardDespawnDistances.put(category, hardDistance);
+ }
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 28d0be9c3391a636fdc04c2e081ed462ed512c5d..57a856cc52db63861d38e1b94c899b47b7572139 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -777,14 +777,14 @@ public abstract class Mob extends LivingEntity {
if (entityhuman != null) {
double d0 = entityhuman.distanceToSqr((Entity) this);
- int i = this.getType().getCategory().getDespawnDistance();
+ int i = this.level.paperConfig.hardDespawnDistances.getInt(this.getType().getCategory()); // Paper - custom despawn distances
int j = i * i;
if (d0 > (double) j && this.removeWhenFarAway(d0)) {
this.discard();
}
- int k = this.getType().getCategory().getNoDespawnDistance();
+ int k = this.level.paperConfig.softDespawnDistances.getInt(this.getType().getCategory()); // Paper - custom despawn distances
int l = k * k;
if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > (double) l && this.removeWhenFarAway(d0)) {

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Thu, 3 Mar 2016 03:53:43 -0600
Subject: [PATCH] Allow for toggling of spawn chunks
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 3afadc8d916714398974d77aa0f1093729e008ca..f32726275d18772904883b618be66893ca5d84fd 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -174,4 +174,10 @@ public class PaperWorldConfig {
hardDespawnDistances.put(category, hardDistance);
}
}
+
+ public boolean keepSpawnInMemory;
+ private void keepSpawnInMemory() {
+ keepSpawnInMemory = getBoolean("keep-spawn-loaded", true);
+ log("Keep spawn chunk loaded: " + keepSpawnInMemory);
+ }
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index d097223e30de74d5347792fb6d0eecb254099f73..1cb128fb60636016db826ab3120d586346d88cec 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -238,6 +238,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
});
// CraftBukkit end
timings = new co.aikar.timings.WorldTimingsHandler(this); // Paper - code below can generate new world and access timings
+ this.keepSpawnInMemory = this.paperConfig.keepSpawnInMemory; // Paper
this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
}

View file

@ -1,82 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Tue, 1 Mar 2016 14:14:15 -0600
Subject: [PATCH] Drop falling block and tnt entities at the specified height
* Dec 2, 2020 Added tnt nerf for tnt minecarts - Machine_Maker
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index f32726275d18772904883b618be66893ca5d84fd..b41f6074e0d88b6becb5b931fc4ee94a1f9f2f0b 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -180,4 +180,14 @@ public class PaperWorldConfig {
keepSpawnInMemory = getBoolean("keep-spawn-loaded", true);
log("Keep spawn chunk loaded: " + keepSpawnInMemory);
}
+
+ public int fallingBlockHeightNerf;
+ public int entityTNTHeightNerf;
+ private void heightNerfs() {
+ fallingBlockHeightNerf = getInt("falling-block-height-nerf", 0);
+ entityTNTHeightNerf = getInt("tnt-entity-height-nerf", 0);
+
+ if (fallingBlockHeightNerf != 0) log("Falling Block Height Limit set to Y: " + fallingBlockHeightNerf);
+ if (entityTNTHeightNerf != 0) log("TNT Entity Height Limit set to Y: " + entityTNTHeightNerf);
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 7e1594e8df4fd09cd1aecbc5f3784797b04a8337..26ab6d0c98560e4dfebbad3482fd308861818e30 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -137,6 +137,17 @@ public class FallingBlockEntity extends Entity {
}
this.move(MoverType.SELF, this.getDeltaMovement());
+
+ // Paper start - Configurable EntityFallingBlock height nerf
+ if (this.level.paperConfig.fallingBlockHeightNerf != 0 && this.getY() > this.level.paperConfig.fallingBlockHeightNerf) {
+ if (this.dropItem && this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
+ this.spawnAtLocation(block);
+ }
+
+ this.discard();
+ return;
+ }
+ // Paper end
if (!this.level.isClientSide) {
BlockPos blockposition = this.blockPosition();
boolean flag = this.blockState.getBlock() instanceof ConcretePowderBlock;
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index e24b46820394c5f220d5bf7c4e763ef95ff9e9ab..bbe15c66917781a8b6950307449f0243ffc3c8c7 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -68,6 +68,12 @@ public class PrimedTnt extends Entity {
}
this.move(MoverType.SELF, this.getDeltaMovement());
+ // Paper start - Configurable TNT entity height nerf
+ if (this.level.paperConfig.entityTNTHeightNerf != 0 && this.getY() > this.level.paperConfig.entityTNTHeightNerf) {
+ this.discard();
+ return;
+ }
+ // Paper end
this.setDeltaMovement(this.getDeltaMovement().scale(0.98D));
if (this.onGround) {
this.setDeltaMovement(this.getDeltaMovement().multiply(0.7D, -0.5D, 0.7D));
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java b/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
index 3e64b1743042a293e2be9e1c16daa979b601e1ed..e430d9214d5abb367fa503e65af463f0e926563e 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartTNT.java
@@ -45,6 +45,12 @@ public class MinecartTNT extends AbstractMinecart {
public void tick() {
super.tick();
if (this.fuse > 0) {
+ // Paper start - Configurable TNT entity height nerf
+ if (this.level.paperConfig.entityTNTHeightNerf != 0 && this.getY() > this.level.paperConfig.entityTNTHeightNerf) {
+ this.discard();
+ return;
+ }
+ // Paper end
--this.fuse;
this.level.addParticle(ParticleTypes.SMOKE, this.getX(), this.getY() + 0.5D, this.getZ(), 0.0D, 0.0D, 0.0D);
} else if (this.fuse == 0) {

View file

@ -1,117 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 1 Mar 2016 14:32:43 -0600
Subject: [PATCH] Show 'Paper' in client crashes, server lists, and Mojang
stats
diff --git a/src/main/java/net/minecraft/server/Eula.java b/src/main/java/net/minecraft/server/Eula.java
index f092497b6defd28c94393e483a9288d121158a1e..df44790b1c342d0a6ff794bea86319fa7498cbae 100644
--- a/src/main/java/net/minecraft/server/Eula.java
+++ b/src/main/java/net/minecraft/server/Eula.java
@@ -64,7 +64,7 @@ public class Eula {
try {
Properties properties = new Properties();
properties.setProperty("eula", "false");
- properties.store(outputStream, "By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).");
+ properties.store(outputStream, "By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).\nYou also agree that tacos are tasty, and the best food in the world."); // Paper - fix lag;
} catch (Throwable var5) {
if (outputStream != null) {
try {
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index f1c94ec44233ce0007a43922d1ca7ba5e71d68bd..eef07309b24e88820d35517dd868fff25f777262 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1456,7 +1456,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@DontObfuscate
public String getServerModName() {
- return "Spigot"; // Spigot - Spigot > // CraftBukkit - cb > vanilla!
+ return "Paper"; // Paper - Paper > // Spigot - Spigot > // CraftBukkit - cb > vanilla!
}
public SystemReport fillSystemReport(SystemReport details) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index a9f3bddd33cf7f7773c262f1b818eed9895987ef..e828759ffc9838451f01cb9312cf2c4cffb5528e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -246,7 +246,7 @@ import org.yaml.snakeyaml.error.MarkedYAMLException;
import net.md_5.bungee.api.chat.BaseComponent; // Spigot
public final class CraftServer implements Server {
- private final String serverName = "CraftBukkit";
+ private final String serverName = "Paper"; // Paper
private final String serverVersion;
private final String bukkitVersion = Versioning.getBukkitVersion();
private final Logger logger = Logger.getLogger("Minecraft");
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index ae4dc96da9e50ce8645e1b5da13e29085e916e98..a0ac6ba17a46bac4c5363a32e078ab89b260bac8 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -216,12 +216,25 @@ public class Main {
deadline.add(Calendar.DAY_OF_YEAR, -21);
if (buildDate.before(deadline.getTime())) {
System.err.println("*** Error, this build is outdated ***");
- System.err.println("*** Please download a new build as per instructions from https://www.spigotmc.org/go/outdated-spigot ***");
+ System.err.println("*** Please download a new build as per instructions from https://papermc.io/downloads ***"); // Paper
System.err.println("*** Server will start in 20 seconds ***");
Thread.sleep(TimeUnit.SECONDS.toMillis(20));
}
}
+ // Paper start - Log Java and OS versioning to help with debugging plugin issues
+ java.lang.management.RuntimeMXBean runtimeMX = java.lang.management.ManagementFactory.getRuntimeMXBean();
+ java.lang.management.OperatingSystemMXBean osMX = java.lang.management.ManagementFactory.getOperatingSystemMXBean();
+ if (runtimeMX != null && osMX != null) {
+ String javaInfo = "Java " + runtimeMX.getSpecVersion() + " (" + runtimeMX.getVmName() + " " + runtimeMX.getVmVersion() + ")";
+ String osInfo = "Host: " + osMX.getName() + " " + osMX.getVersion() + " (" + osMX.getArch() + ")";
+
+ System.out.println("System Info: " + javaInfo + " " + osInfo);
+ } else {
+ System.out.println("Unable to read system info");
+ }
+ // Paper end
+
System.out.println("Loading libraries, please wait...");
net.minecraft.server.Main.main(options);
} catch (Throwable t) {
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index 335120afc88a8fc1543c2e6df516fd728e3ab032..d5863b0b06384b25eaa33572fa02649795463ed8 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -19,7 +19,7 @@ public class WatchdogThread extends Thread
private WatchdogThread(long timeoutTime, boolean restart)
{
- super( "Spigot Watchdog Thread" );
+ super( "Paper Watchdog Thread" );
this.timeoutTime = timeoutTime;
this.restart = restart;
}
@@ -65,14 +65,14 @@ public class WatchdogThread extends Thread
{
Logger log = Bukkit.getServer().getLogger();
log.log( Level.SEVERE, "------------------------------" );
- log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Spigot bug." );
+ log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper
log.log( Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author" );
log.log( Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring" );
log.log( Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once" );
log.log( Level.SEVERE, "\t If this is the case, consider increasing timeout-time in spigot.yml but note that this will replace the crash with LARGE lag spikes" );
- log.log( Level.SEVERE, "If you are unsure or still think this is a Spigot bug, please report to https://www.spigotmc.org/" );
+ log.log( Level.SEVERE, "If you are unsure or still think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues" );
log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" );
- log.log( Level.SEVERE, "Spigot version: " + Bukkit.getServer().getVersion() );
+ log.log( Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion() );
//
if ( net.minecraft.world.level.Level.lastPhysicsProblem != null )
{
@@ -82,7 +82,7 @@ public class WatchdogThread extends Thread
}
//
log.log( Level.SEVERE, "------------------------------" );
- log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Spigot!):" );
+ log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
log.log( Level.SEVERE, "------------------------------" );
//

View file

@ -1,157 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach@zachbr.io>
Date: Mon, 27 May 2019 03:40:05 -0500
Subject: [PATCH] Implement Paper VersionChecker
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..351159bbdb0c8045f4983f54dee34430dbcc423e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -0,0 +1,129 @@
+package com.destroystokyo.paper;
+
+import com.destroystokyo.paper.util.VersionFetcher;
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import com.google.gson.*;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.event.ClickEvent;
+import net.kyori.adventure.text.format.NamedTextColor;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.stream.StreamSupport;
+
+public class PaperVersionFetcher implements VersionFetcher {
+ private static final java.util.regex.Pattern VER_PATTERN = java.util.regex.Pattern.compile("^([0-9\\.]*)\\-.*R"); // R is an anchor, will always give '-R' at end
+ private static final String GITHUB_BRANCH_NAME = "master";
+ private static final String DOWNLOAD_PAGE = "https://papermc.io/downloads";
+ private static @Nullable String mcVer;
+
+ @Override
+ public long getCacheTime() {
+ return 720000;
+ }
+
+ @Nonnull
+ @Override
+ public Component getVersionMessage(@Nonnull String serverVersion) {
+ String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]");
+ return getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]);
+ }
+
+ private static @Nullable String getMinecraftVersion() {
+ if (mcVer == null) {
+ java.util.regex.Matcher matcher = VER_PATTERN.matcher(org.bukkit.Bukkit.getBukkitVersion());
+ if (matcher.find()) {
+ String result = matcher.group();
+ mcVer = result.substring(0, result.length() - 2); // strip 'R' anchor and trailing '-'
+ } else {
+ org.bukkit.Bukkit.getLogger().warning("Unable to match version to pattern! Report to PaperMC!");
+ org.bukkit.Bukkit.getLogger().warning("Pattern: " + VER_PATTERN.toString());
+ org.bukkit.Bukkit.getLogger().warning("Version: " + org.bukkit.Bukkit.getBukkitVersion());
+ }
+ }
+
+ return mcVer;
+ }
+
+ private static Component getUpdateStatusMessage(@Nonnull String repo, @Nonnull String branch, @Nonnull String versionInfo) {
+ int distance;
+ try {
+ int jenkinsBuild = Integer.parseInt(versionInfo);
+ distance = fetchDistanceFromSiteApi(jenkinsBuild, getMinecraftVersion());
+ } catch (NumberFormatException ignored) {
+ versionInfo = versionInfo.replace("\"", "");
+ distance = fetchDistanceFromGitHub(repo, branch, versionInfo);
+ }
+
+ switch (distance) {
+ case -1:
+ return Component.text("Error obtaining version information", NamedTextColor.YELLOW);
+ case 0:
+ return Component.text("You are running the latest version", NamedTextColor.GREEN);
+ case -2:
+ return Component.text("Unknown version", NamedTextColor.YELLOW);
+ default:
+ return Component.text("You are " + distance + " version(s) behind", NamedTextColor.YELLOW)
+ .append(Component.newline())
+ .append(Component.text("Download the new version at: ")
+ .append(Component.text(DOWNLOAD_PAGE, NamedTextColor.GOLD)
+ .hoverEvent(Component.text("Click to open", NamedTextColor.WHITE))
+ .clickEvent(ClickEvent.openUrl(DOWNLOAD_PAGE))));
+ }
+ }
+
+ private static int fetchDistanceFromSiteApi(int jenkinsBuild, @Nullable String siteApiVersion) {
+ if (siteApiVersion == null) { return -1; }
+ try {
+ try (BufferedReader reader = Resources.asCharSource(
+ new URL("https://api.papermc.io/v2/projects/paper/versions/" + siteApiVersion),
+ Charsets.UTF_8
+ ).openBufferedStream()) {
+ JsonObject json = new Gson().fromJson(reader, JsonObject.class);
+ JsonArray builds = json.getAsJsonArray("builds");
+ int latest = StreamSupport.stream(builds.spliterator(), false)
+ .mapToInt(e -> e.getAsInt())
+ .max()
+ .getAsInt();
+ return latest - jenkinsBuild;
+ } catch (JsonSyntaxException ex) {
+ ex.printStackTrace();
+ return -1;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+
+ // Contributed by Techcable <Techcable@outlook.com> in GH-65
+ private static int fetchDistanceFromGitHub(@Nonnull String repo, @Nonnull String branch, @Nonnull String hash) {
+ try {
+ HttpURLConnection connection = (HttpURLConnection) new URL("https://api.github.com/repos/" + repo + "/compare/" + branch + "..." + hash).openConnection();
+ connection.connect();
+ if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) return -2; // Unknown commit
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8))) {
+ JsonObject obj = new Gson().fromJson(reader, JsonObject.class);
+ String status = obj.get("status").getAsString();
+ switch (status) {
+ case "identical":
+ return 0;
+ case "behind":
+ return obj.get("behind_by").getAsInt();
+ default:
+ return -1;
+ }
+ } catch (JsonSyntaxException | NumberFormatException e) {
+ e.printStackTrace();
+ return -1;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index 6c5dfff9616cf6bbfc09471a3a81059acb4ffcbb..a47f81c690b9d2a63c21f126ca2727a1d23e626c 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -421,6 +421,11 @@ public final class CraftMagicNumbers implements UnsafeValues {
public String getTimingsServerName() {
return com.destroystokyo.paper.PaperConfig.timingsServerName;
}
+
+ @Override
+ public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
+ return new com.destroystokyo.paper.PaperVersionFetcher();
+ }
// Paper end
/**

View file

@ -1,214 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kyle Wood <kyle@denwav.dev>
Date: Thu, 1 Mar 2018 19:37:52 -0600
Subject: [PATCH] Add version history to version command
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
index 351159bbdb0c8045f4983f54dee34430dbcc423e..bf42969859545a8a520923ef1836ffa4a5cc24a0 100644
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -7,6 +7,8 @@ import com.google.gson.*;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
+import net.kyori.adventure.text.format.TextDecoration;
+import net.kyori.adventure.text.TextComponent;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -30,7 +32,10 @@ public class PaperVersionFetcher implements VersionFetcher {
@Override
public Component getVersionMessage(@Nonnull String serverVersion) {
String[] parts = serverVersion.substring("git-Paper-".length()).split("[-\\s]");
- return getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]);
+ final Component updateMessage = getUpdateStatusMessage("PaperMC/Paper", GITHUB_BRANCH_NAME, parts[0]);
+ final Component history = getHistory();
+
+ return history != null ? TextComponent.ofChildren(updateMessage, Component.newline(), history) : updateMessage;
}
private static @Nullable String getMinecraftVersion() {
@@ -126,4 +131,19 @@ public class PaperVersionFetcher implements VersionFetcher {
return -1;
}
}
+
+ @Nullable
+ private Component getHistory() {
+ final VersionHistoryManager.VersionData data = VersionHistoryManager.INSTANCE.getVersionData();
+ if (data == null) {
+ return null;
+ }
+
+ final String oldVersion = data.getOldVersion();
+ if (oldVersion == null) {
+ return null;
+ }
+
+ return Component.text("Previous version: " + oldVersion, NamedTextColor.GRAY, TextDecoration.ITALIC);
+ }
}
diff --git a/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java b/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..aac3f66cb23d260729c2a48d8710a9de2346aa22
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java
@@ -0,0 +1,145 @@
+package com.destroystokyo.paper;
+
+import com.google.common.base.MoreObjects;
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.bukkit.Bukkit;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public enum VersionHistoryManager {
+ INSTANCE;
+
+ private final Gson gson = new Gson();
+
+ private final Logger logger = Bukkit.getLogger();
+
+ private VersionData currentData = null;
+
+ VersionHistoryManager() {
+ final Path path = Paths.get("version_history.json");
+
+ if (Files.exists(path)) {
+ // Basic file santiy checks
+ if (!Files.isRegularFile(path)) {
+ if (Files.isDirectory(path)) {
+ logger.severe(path + " is a directory, cannot be used for version history");
+ } else {
+ logger.severe(path + " is not a regular file, cannot be used for version history");
+ }
+ // We can't continue
+ return;
+ }
+
+ try (final BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
+ currentData = gson.fromJson(reader, VersionData.class);
+ } catch (final IOException e) {
+ logger.log(Level.SEVERE, "Failed to read version history file '" + path + "'", e);
+ return;
+ } catch (final JsonSyntaxException e) {
+ logger.log(Level.SEVERE, "Invalid json syntax for file '" + path + "'", e);
+ return;
+ }
+
+ final String version = Bukkit.getVersion();
+ if (version == null) {
+ logger.severe("Failed to retrieve current version");
+ return;
+ }
+
+ if (!version.equals(currentData.getCurrentVersion())) {
+ // The version appears to have changed
+ currentData.setOldVersion(currentData.getCurrentVersion());
+ currentData.setCurrentVersion(version);
+ writeFile(path);
+ }
+ } else {
+ // File doesn't exist, start fresh
+ currentData = new VersionData();
+ // oldVersion is null
+ currentData.setCurrentVersion(Bukkit.getVersion());
+ writeFile(path);
+ }
+ }
+
+ private void writeFile(@Nonnull final Path path) {
+ try (final BufferedWriter writer = Files.newBufferedWriter(
+ path,
+ StandardCharsets.UTF_8,
+ StandardOpenOption.WRITE,
+ StandardOpenOption.CREATE,
+ StandardOpenOption.TRUNCATE_EXISTING
+ )) {
+ gson.toJson(currentData, writer);
+ } catch (final IOException e) {
+ logger.log(Level.SEVERE, "Failed to write to version history file", e);
+ }
+ }
+
+ @Nullable
+ public VersionData getVersionData() {
+ return currentData;
+ }
+
+ public static class VersionData {
+ private String oldVersion;
+
+ private String currentVersion;
+
+ @Nullable
+ public String getOldVersion() {
+ return oldVersion;
+ }
+
+ public void setOldVersion(@Nullable String oldVersion) {
+ this.oldVersion = oldVersion;
+ }
+
+ @Nullable
+ public String getCurrentVersion() {
+ return currentVersion;
+ }
+
+ public void setCurrentVersion(@Nullable String currentVersion) {
+ this.currentVersion = currentVersion;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("oldVersion", oldVersion)
+ .add("currentVersion", currentVersion)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final VersionData versionData = (VersionData) o;
+ return Objects.equals(oldVersion, versionData.oldVersion) &&
+ Objects.equals(currentVersion, versionData.currentVersion);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(oldVersion, currentVersion);
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 1c0fefd539ef82d2d1b33a4974d67dc35ded0e1f..20ff08f1a802d16d2306b570e9fb529946d90f6b 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -204,6 +204,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
return false;
}
com.destroystokyo.paper.PaperConfig.registerCommands();
+ com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now
// Paper end
this.setPvpAllowed(dedicatedserverproperties.pvp);

View file

@ -1,143 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jedediah Smith <jedediah@silencegreys.com>
Date: Tue, 1 Mar 2016 14:47:52 -0600
Subject: [PATCH] Player affects spawning API
diff --git a/src/main/java/net/minecraft/world/entity/EntitySelector.java b/src/main/java/net/minecraft/world/entity/EntitySelector.java
index 5c3b11f738c1ea19981cc878aa6c2323497391a0..b91a61be7c4829fce0ff8da290eab580e20bb78d 100644
--- a/src/main/java/net/minecraft/world/entity/EntitySelector.java
+++ b/src/main/java/net/minecraft/world/entity/EntitySelector.java
@@ -29,6 +29,11 @@ public final class EntitySelector {
public static final Predicate<Entity> CAN_BE_COLLIDED_WITH = EntitySelector.NO_SPECTATORS.and(Entity::canBeCollidedWith);
private EntitySelector() {}
+ // Paper start
+ public static final Predicate<Entity> affectsSpawning = (entity) -> {
+ return !entity.isSpectator() && entity.isAlive() && (entity instanceof net.minecraft.server.level.ServerPlayer) && ((net.minecraft.server.level.ServerPlayer) entity).affectsSpawning;
+ };
+ // Paper end
public static Predicate<Entity> withinDistance(double x, double y, double z, double max) {
double d4 = max * max;
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 57a856cc52db63861d38e1b94c899b47b7572139..3d54fa71b2d3532e93fe3636a86150e10fcba31a 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -773,7 +773,7 @@ public abstract class Mob extends LivingEntity {
if (this.level.getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
this.discard();
} else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
- Player entityhuman = this.level.getNearestPlayer(this, -1.0D);
+ Player entityhuman = this.level.findNearbyPlayer(this, -1.0D, EntitySelector.affectsSpawning); // Paper
if (entityhuman != null) {
double d0 = entityhuman.distanceToSqr((Entity) this);
diff --git a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
index 6eaedfabf70b604705ad9a772a2e602c8590b500..97c2c1647fa12650e5963c7c1c746fec2429e3d7 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Silverfish.java
@@ -127,7 +127,7 @@ public class Silverfish extends Monster {
if (checkAnyLightMonsterSpawnRules(type, world, spawnReason, pos, random)) {
Player entityhuman = world.getNearestPlayer((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, 5.0D, true);
- return entityhuman == null;
+ return !(entityhuman != null && !entityhuman.affectsSpawning) && entityhuman == null; // Paper - Affects Spawning API
} else {
return false;
}
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index 1d4d3d6fc8affde249fb7cda8a3a488b6689130a..067513b240db88b818bd26d74c31fb5f8ee80f5d 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -175,6 +175,9 @@ public abstract class Player extends LivingEntity {
private final ItemCooldowns cooldowns;
@Nullable
public FishingHook fishing;
+ // Paper start
+ public boolean affectsSpawning = true;
+ // Paper end
// CraftBukkit start
public boolean fauxSleeping;
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 212b23a380a4bcdb1d2995ca2ccfc8a1709691bd..31bfc0c491c9a4cc6782b6c284121f96972517ea 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -51,7 +51,7 @@ public abstract class BaseSpawner {
}
public boolean isNearPlayer(Level world, BlockPos pos) {
- return world.hasNearbyAlivePlayer((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange);
+ return world.isAffectsSpawningPlayerNearby((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, (double) this.requiredPlayerRange); // Paper
}
public void clientTick(Level world, BlockPos pos) {
diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java
index 7c5918f84d2b8f9c778258b7e7d745105effb082..cfb286020b8ee87bad7edbda4cd0b999fb607a06 100644
--- a/src/main/java/net/minecraft/world/level/EntityGetter.java
+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java
@@ -70,8 +70,8 @@ public interface EntityGetter {
}
}
- @Nullable
- default Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate<Entity> targetPredicate) {
+ default Player findNearbyPlayer(Entity entity, double d0, @Nullable Predicate<Entity> predicate) { return this.getNearestPlayer(entity.getX(), entity.getY(), entity.getZ(), d0, predicate); } // Paper
+ @Nullable default Player getNearestPlayer(double x, double y, double z, double maxDistance, @Nullable Predicate<Entity> targetPredicate) { // Paper
double d = -1.0D;
Player player = null;
@@ -99,6 +99,27 @@ public interface EntityGetter {
return this.getNearestPlayer(x, y, z, maxDistance, predicate);
}
+ // Paper end
+ default boolean isAffectsSpawningPlayerNearby(double d0, double d1, double d2, double d3) {
+ java.util.Iterator iterator = this.players().iterator();
+ double d4;
+ do {
+ Player entityhuman;
+ do {
+ if (!iterator.hasNext()) {
+ return false;
+ }
+
+ entityhuman = (Player) iterator.next();
+ } while (!EntitySelector.affectsSpawning.test(entityhuman));
+
+ d4 = entityhuman.distanceToSqr(d0, d1, d2);
+ } while (d3 >= 0.0D && d4 >= d3 * d3);
+
+ return true;
+ }
+ // Paper end
+
default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) {
for(Player player : this.players()) {
if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index b3769c6d96d33d870c38349f1a6255dbf840089a..0e153d6e1df199a7b2af73c44e7fe784c7d1947c 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1961,8 +1961,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public String getLocale() {
return this.getHandle().locale;
+
+ }
+
+ // Paper start
+ public void setAffectsSpawning(boolean affects) {
+ this.getHandle().affectsSpawning = affects;
}
+ @Override
+ public boolean getAffectsSpawning() {
+ return this.getHandle().affectsSpawning;
+ }
+ // Paper end
+
@Override
public void updateCommands() {
if (this.getHandle().connection == null) return;

View file

@ -1,212 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 1 Mar 2016 23:09:29 -0600
Subject: [PATCH] Further improve server tick loop
Improves how the catchup buffer is handled, allowing it to roll both ways
increasing the effeciency of the thread sleep so it only will sleep once.
Also increases the buffer of the catchup to ensure server stays at 20 TPS unless extreme conditions
Previous implementation did not calculate TPS correctly.
Switch to a realistic rolling average and factor in std deviation as an extra reporting variable
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index eef07309b24e88820d35517dd868fff25f777262..e26818bd6fb2216ab9b363affe99e4b6c83cca6a 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -282,7 +282,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public org.bukkit.command.ConsoleCommandSender console;
public org.bukkit.command.RemoteConsoleCommandSender remoteConsole;
public ConsoleReader reader;
- public static int currentTick = (int) (System.currentTimeMillis() / 50);
+ public static int currentTick = 0; // Paper - Further improve tick loop
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
public int autosavePeriod;
public Commands vanillaCommandDispatcher;
@@ -291,7 +291,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Spigot start
public static final int TPS = 20;
public static final int TICK_TIME = 1000000000 / MinecraftServer.TPS;
- private static final int SAMPLE_INTERVAL = 100;
+ private static final int SAMPLE_INTERVAL = 20; // Paper
public final double[] recentTps = new double[ 3 ];
// Spigot end
public static long currentTickLong = 0L; // Paper
@@ -1003,6 +1003,57 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
{
return ( avg * exp ) + ( tps * ( 1 - exp ) );
}
+
+ // Paper start - Further improve server tick loop
+ private static final long SEC_IN_NANO = 1000000000;
+ private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L;
+ private long lastTick = 0;
+ private long catchupTime = 0;
+ public final RollingAverage tps1 = new RollingAverage(60);
+ public final RollingAverage tps5 = new RollingAverage(60 * 5);
+ public final RollingAverage tps15 = new RollingAverage(60 * 15);
+
+ public static class RollingAverage {
+ private final int size;
+ private long time;
+ private java.math.BigDecimal total;
+ private int index = 0;
+ private final java.math.BigDecimal[] samples;
+ private final long[] times;
+
+ RollingAverage(int size) {
+ this.size = size;
+ this.time = size * SEC_IN_NANO;
+ this.total = dec(TPS).multiply(dec(SEC_IN_NANO)).multiply(dec(size));
+ this.samples = new java.math.BigDecimal[size];
+ this.times = new long[size];
+ for (int i = 0; i < size; i++) {
+ this.samples[i] = dec(TPS);
+ this.times[i] = SEC_IN_NANO;
+ }
+ }
+
+ private static java.math.BigDecimal dec(long t) {
+ return new java.math.BigDecimal(t);
+ }
+ public void add(java.math.BigDecimal x, long t) {
+ time -= times[index];
+ total = total.subtract(samples[index].multiply(dec(times[index])));
+ samples[index] = x;
+ times[index] = t;
+ time += t;
+ total = total.add(x.multiply(dec(t)));
+ if (++index == size) {
+ index = 0;
+ }
+ }
+
+ public double getAverage() {
+ return total.divide(dec(time), 30, java.math.RoundingMode.HALF_UP).doubleValue();
+ }
+ }
+ private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal(1E9).multiply(new java.math.BigDecimal(SAMPLE_INTERVAL));
+ // Paper End
// Spigot End
protected void runServer() {
@@ -1015,26 +1066,33 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Spigot start
Arrays.fill( recentTps, 20 );
- long curTime, tickSection = Util.getMillis(), tickCount = 1;
+ long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop
+ lastTick = start - TICK_TIME; // Paper
while (this.running) {
- long i = (curTime = Util.getMillis()) - this.nextTickTime;
+ long i = ((curTime = System.nanoTime()) / (1000L * 1000L)) - this.nextTickTime; // Paper
if (i > 5000L && this.nextTickTime - this.lastOverloadWarning >= 30000L) { // CraftBukkit
long j = i / 50L;
if (this.server.getWarnOnOverload()) // CraftBukkit
- MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j);
+ MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j);
this.nextTickTime += j * 50L;
this.lastOverloadWarning = this.nextTickTime;
}
++MinecraftServer.currentTickLong; // Paper
- if ( tickCount++ % MinecraftServer.SAMPLE_INTERVAL == 0 )
+ if ( ++MinecraftServer.currentTick % MinecraftServer.SAMPLE_INTERVAL == 0 )
{
- double currentTps = 1E3 / ( curTime - tickSection ) * MinecraftServer.SAMPLE_INTERVAL;
- this.recentTps[0] = MinecraftServer.calcTps( this.recentTps[0], 0.92, currentTps ); // 1/exp(5sec/1min)
- this.recentTps[1] = MinecraftServer.calcTps( this.recentTps[1], 0.9835, currentTps ); // 1/exp(5sec/5min)
- this.recentTps[2] = MinecraftServer.calcTps( this.recentTps[2], 0.9945, currentTps ); // 1/exp(5sec/15min)
+ final long diff = curTime - tickSection;
+ java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP);
+ tps1.add(currentTps, diff);
+ tps5.add(currentTps, diff);
+ tps15.add(currentTps, diff);
+ // Backwards compat with bad plugins
+ this.recentTps[0] = tps1.getAverage();
+ this.recentTps[1] = tps5.getAverage();
+ this.recentTps[2] = tps15.getAverage();
+ // Paper end
tickSection = curTime;
}
// Spigot end
@@ -1044,7 +1102,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount);
}
- MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit
+ //MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit // Paper - don't overwrite current tick time
+ lastTick = curTime;
this.nextTickTime += 50L;
this.startMetricsRecordingTick();
this.profiler.push("tick");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index e828759ffc9838451f01cb9312cf2c4cffb5528e..46f895acd74de17784d0c5efc66caf10a8be8686 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2391,6 +2391,17 @@ public final class CraftServer implements Server {
return CraftMagicNumbers.INSTANCE;
}
+ // Paper - Add getTPS API - Further improve tick loop
+ @Override
+ public double[] getTPS() {
+ return new double[] {
+ net.minecraft.server.MinecraftServer.getServer().tps1.getAverage(),
+ net.minecraft.server.MinecraftServer.getServer().tps5.getAverage(),
+ net.minecraft.server.MinecraftServer.getServer().tps15.getAverage()
+ };
+ }
+ // Paper end
+
// Spigot start
private final org.bukkit.Server.Spigot spigot = new org.bukkit.Server.Spigot()
{
diff --git a/src/main/java/org/spigotmc/TicksPerSecondCommand.java b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
index 4ab81a99f906e3f28e026d0e50b5b943c1bdcfb5..9bede6a26c08ede063c7a38f1149c811df14b258 100644
--- a/src/main/java/org/spigotmc/TicksPerSecondCommand.java
+++ b/src/main/java/org/spigotmc/TicksPerSecondCommand.java
@@ -24,22 +24,30 @@ public class TicksPerSecondCommand extends Command
return true;
}
- StringBuilder sb = new StringBuilder( ChatColor.GOLD + "TPS from last 1m, 5m, 15m: " );
- for ( double tps : MinecraftServer.getServer().recentTps )
- {
- sb.append( this.format( tps ) );
- sb.append( ", " );
+ // Paper start - Further improve tick handling
+ double[] tps = org.bukkit.Bukkit.getTPS();
+ String[] tpsAvg = new String[tps.length];
+
+ for ( int i = 0; i < tps.length; i++) {
+ tpsAvg[i] = TicksPerSecondCommand.format( tps[i] );
+ }
+ sender.sendMessage(ChatColor.GOLD + "TPS from last 1m, 5m, 15m: " + org.apache.commons.lang.StringUtils.join(tpsAvg, ", "));
+ if (args.length > 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) {
+ sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)");
+ if (!hasShownMemoryWarning) {
+ sender.sendMessage(ChatColor.RED + "Warning: " + ChatColor.GOLD + " Memory usage on modern garbage collectors is not a stable value and it is perfectly normal to see it reach max. Please do not pay it much attention.");
+ hasShownMemoryWarning = true;
+ }
}
- sender.sendMessage( sb.substring( 0, sb.length() - 2 ) );
- sender.sendMessage(ChatColor.GOLD + "Current Memory Usage: " + ChatColor.GREEN + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: "
- + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)");
+ // Paper end
return true;
}
- private String format(double tps)
+ private boolean hasShownMemoryWarning; // Paper
+ private static String format(double tps) // Paper - Made static
{
return ( ( tps > 18.0 ) ? ChatColor.GREEN : ( tps > 16.0 ) ? ChatColor.YELLOW : ChatColor.RED ).toString()
- + ( ( tps > 20.0 ) ? "*" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 );
+ + ( ( tps > 21.0 ) ? "*" : "" ) + Math.min( Math.round( tps * 100.0 ) / 100.0, 20.0 ); // Paper - only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise
}
}

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 1 Mar 2016 23:12:03 -0600
Subject: [PATCH] Only refresh abilities if needed
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 0e153d6e1df199a7b2af73c44e7fe784c7d1947c..6c866e9fc091b8f2b982d5554f381bfed7d669a9 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1630,12 +1630,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public void setFlying(boolean value) {
+ boolean needsUpdate = getHandle().getAbilities().flying != value; // Paper - Only refresh abilities if needed
if (!this.getAllowFlight() && value) {
throw new IllegalArgumentException("Cannot make player fly if getAllowFlight() is false");
}
this.getHandle().getAbilities().flying = value;
- this.getHandle().onUpdateAbilities();
+ if (needsUpdate) this.getHandle().onUpdateAbilities(); // Paper - Only refresh abilities if needed
}
@Override

View file

@ -1,159 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Tue, 1 Mar 2016 23:45:08 -0600
Subject: [PATCH] Entity Origin API
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0750cf27c1b2cac723d68d0e6c2204cbb5795571..0eb0229125fd027025b6b44dfceddf626fc05399 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2027,6 +2027,15 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
entity.valid = true; // CraftBukkit
+ // Paper start - Set origin location when the entity is being added to the world
+ if (entity.getOriginVector() == null) {
+ entity.setOrigin(entity.getBukkitEntity().getLocation());
+ }
+ // Default to current world if unknown, gross assumption but entities rarely change world
+ if (entity.getOriginWorld() == null) {
+ entity.setOrigin(entity.getOriginVector().toLocation(getWorld()));
+ }
+ // Paper end
}
public void onTrackingEnd(Entity entity) {
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index d778209604c71a0728748dac91a5cb993f4357b7..ae6c1abe1443f3758fce35a20387f0ed93748af5 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -300,7 +300,27 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
public long activatedTick = Integer.MIN_VALUE;
public void inactiveTick() { }
// Spigot end
+ // Paper start
+ @javax.annotation.Nullable
+ private org.bukkit.util.Vector origin;
+ @javax.annotation.Nullable
+ private UUID originWorld;
+
+ public void setOrigin(@javax.annotation.Nonnull Location location) {
+ this.origin = location.toVector();
+ this.originWorld = location.getWorld().getUID();
+ }
+ @javax.annotation.Nullable
+ public org.bukkit.util.Vector getOriginVector() {
+ return this.origin != null ? this.origin.clone() : null;
+ }
+
+ @javax.annotation.Nullable
+ public UUID getOriginWorld() {
+ return this.originWorld;
+ }
+ // Paper end
public float getBukkitYaw() {
return this.yRot;
}
@@ -1822,6 +1842,15 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
this.bukkitEntity.storeBukkitValues(nbt);
}
// CraftBukkit end
+ // Paper start - Save the entity's origin location
+ if (this.origin != null) {
+ UUID originWorld = this.originWorld != null ? this.originWorld : this.level != null ? this.level.getWorld().getUID() : null;
+ if (originWorld != null) {
+ nbt.putUUID("Paper.OriginWorld", originWorld);
+ }
+ nbt.put("Paper.Origin", this.newDoubleList(origin.getX(), origin.getY(), origin.getZ()));
+ }
+ // Paper end
return nbt;
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT");
@@ -1946,6 +1975,20 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
// CraftBukkit end
+ // Paper start - Restore the entity's origin location
+ ListTag originTag = nbt.getList("Paper.Origin", 6);
+ if (!originTag.isEmpty()) {
+ UUID originWorld = null;
+ if (nbt.contains("Paper.OriginWorld")) {
+ originWorld = nbt.getUUID("Paper.OriginWorld");
+ } else if (this.level != null) {
+ originWorld = this.level.getWorld().getUID();
+ }
+ this.originWorld = originWorld;
+ origin = new org.bukkit.util.Vector(originTag.getDouble(0), originTag.getDouble(1), originTag.getDouble(2));
+ }
+ // Paper end
+
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT");
CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being loaded");
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 26ab6d0c98560e4dfebbad3482fd308861818e30..242e02646b8584a8d2a512374ad03729661d584f 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -337,6 +337,14 @@ public class FallingBlockEntity extends Entity {
this.blockState = Blocks.SAND.defaultBlockState();
}
+ // Paper start - Try and load origin location from the old NBT tags for backwards compatibility
+ if (nbt.contains("SourceLoc_x")) {
+ int srcX = nbt.getInt("SourceLoc_x");
+ int srcY = nbt.getInt("SourceLoc_y");
+ int srcZ = nbt.getInt("SourceLoc_z");
+ this.setOrigin(new org.bukkit.Location(level.getWorld(), srcX, srcY, srcZ));
+ }
+ // Paper end
}
public void setHurtsEntities(float fallHurtAmount, int fallHurtMax) {
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index bbe15c66917781a8b6950307449f0243ffc3c8c7..dfcca1fac06de7a4be9be3c238a738a0599fcd24 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -120,6 +120,14 @@ public class PrimedTnt extends Entity {
@Override
protected void readAdditionalSaveData(CompoundTag nbt) {
this.setFuse(nbt.getShort("Fuse"));
+ // Paper start - Try and load origin location from the old NBT tags for backwards compatibility
+ if (nbt.contains("SourceLoc_x")) {
+ int srcX = nbt.getInt("SourceLoc_x");
+ int srcY = nbt.getInt("SourceLoc_y");
+ int srcZ = nbt.getInt("SourceLoc_z");
+ this.setOrigin(new org.bukkit.Location(level.getWorld(), srcX, srcY, srcZ));
+ }
+ // Paper end
}
@Nullable
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 4b7ed15279bbdd116d993f190094f80c888aed69..fdbcf4989f72e1604a2841f565adfeebf8d45622 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1154,4 +1154,21 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return this.spigot;
}
// Spigot end
+
+ // Paper start
+ @Override
+ public Location getOrigin() {
+ Vector originVector = this.getHandle().getOriginVector();
+ if (originVector == null) {
+ return null;
+ }
+ World world = this.getWorld();
+ if (this.getHandle().getOriginWorld() != null) {
+ world = org.bukkit.Bukkit.getWorld(this.getHandle().getOriginWorld());
+ }
+
+ //noinspection ConstantConditions
+ return originVector.toLocation(world);
+ }
+ // Paper end
}

View file

@ -1,66 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 1 Mar 2016 23:52:34 -0600
Subject: [PATCH] Prevent tile entity and entity crashes
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 1cb128fb60636016db826ab3120d586346d88cec..8653fa072825c024e0fb620bdada4adc936b0490 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -736,11 +736,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
try {
tickConsumer.accept(entity);
} catch (Throwable throwable) {
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking entity");
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Entity being ticked");
-
- entity.fillCrashReportCategory(crashreportsystemdetails);
- throw new ReportedException(crashreport);
+ // Paper start - Prevent tile entity and entity crashes
+ final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
+ MinecraftServer.LOGGER.error(msg, throwable);
+ entity.discard();
+ // Paper end
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
index be08224c8107aab3e9a3645a20977dd14bfff782..c518704386f14cd033307dd976455c35760d7236 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -213,7 +213,12 @@ public abstract class BlockEntity {
return minecraftkey + " // " + this.getClass().getCanonicalName();
});
if (this.level != null) {
- CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, this.getBlockState());
+ // Paper start - Prevent TileEntity and Entity crashes
+ BlockState block = this.getBlockState();
+ if (block != null) {
+ CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, block);
+ }
+ // Paper end
CrashReportCategory.populateBlockDetails(crashReportSection, this.level, this.worldPosition, this.level.getBlockState(this.worldPosition));
}
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 5496c9ae4af9658164098356532da47351808b51..ed6203119fe2e4ee47a2d51c84df5b7c236f32da 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1024,11 +1024,11 @@ public class LevelChunk extends ChunkAccess {
gameprofilerfiller.pop();
} catch (Throwable throwable) {
- CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking block entity");
- CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block entity being ticked");
-
- this.blockEntity.fillCrashReportCategory(crashreportsystemdetails);
- throw new ReportedException(crashreport);
+ // Paper start - Prevent tile entity and entity crashes
+ final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
+ net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
+ LevelChunk.this.removeBlockEntity(this.getPos());
+ // Paper end
// Spigot start
} finally {
this.blockEntity.tickTimer.stopTiming();

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 1 Mar 2016 23:58:50 -0600
Subject: [PATCH] Configurable top of nether void damage
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index b41f6074e0d88b6becb5b931fc4ee94a1f9f2f0b..10c08ed945f950b9c2a5e308f8caa11955cb0088 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -190,4 +190,19 @@ public class PaperWorldConfig {
if (fallingBlockHeightNerf != 0) log("Falling Block Height Limit set to Y: " + fallingBlockHeightNerf);
if (entityTNTHeightNerf != 0) log("TNT Entity Height Limit set to Y: " + entityTNTHeightNerf);
}
+
+ public int netherVoidTopDamageHeight;
+ public boolean doNetherTopVoidDamage() { return netherVoidTopDamageHeight > 0; }
+ private void netherVoidTopDamageHeight() {
+ netherVoidTopDamageHeight = getInt("nether-ceiling-void-damage-height", 0);
+ log("Top of the nether void damage height: " + netherVoidTopDamageHeight);
+
+ if (PaperConfig.version < 18) {
+ boolean legacy = getBoolean("nether-ceiling-void-damage", false);
+ if (legacy) {
+ netherVoidTopDamageHeight = 128;
+ set("nether-ceiling-void-damage-height", netherVoidTopDamageHeight);
+ }
+ }
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index ae6c1abe1443f3758fce35a20387f0ed93748af5..2f35ce076a468ac260e28ba90ac55f7717ee1b13 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -648,7 +648,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
public void checkOutOfWorld() {
- if (this.getY() < (double) (this.level.getMinBuildHeight() - 64)) {
+ // Paper start - Configurable nether ceiling damage
+ if (this.getY() < (double) (this.level.getMinBuildHeight() - 64) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER
+ && level.paperConfig.doNetherTopVoidDamage()
+ && this.getY() >= this.level.paperConfig.netherVoidTopDamageHeight)) {
+ // Paper end
this.outOfWorld();
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Wed, 2 Mar 2016 00:03:55 -0600
Subject: [PATCH] Check online mode before converting and renaming player data
diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
index 86fb11e9e197357871d603c4f8ce778660d507cf..0132eb685dbcf3d3402096bd34513e91d2b20abd 100644
--- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
+++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
@@ -56,7 +56,7 @@ public class PlayerDataStorage {
File file = new File(this.playerDir, player.getStringUUID() + ".dat");
// Spigot Start
boolean usingWrongFile = false;
- if ( !file.exists() )
+ if ( org.bukkit.Bukkit.getOnlineMode() && !file.exists() ) // Paper - Check online mode first
{
file = new File( this.playerDir, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + player.getScoreboardName() ).getBytes( "UTF-8" ) ).toString() + ".dat");
if ( file.exists() )

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Wed, 2 Mar 2016 00:32:25 -0600
Subject: [PATCH] Always tick falling blocks
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
index 38cf408899cef72bc9d2888109a7ac7ce0aec638..07e5ece37af6b02210920ce6cc31738274d447a9 100644
--- a/src/main/java/org/spigotmc/ActivationRange.java
+++ b/src/main/java/org/spigotmc/ActivationRange.java
@@ -89,6 +89,7 @@ public class ActivationRange
|| entity instanceof AbstractHurtingProjectile
|| entity instanceof LightningBolt
|| entity instanceof PrimedTnt
+ || entity instanceof net.minecraft.world.entity.item.FallingBlockEntity // Paper - Always tick falling blocks
|| entity instanceof EndCrystal
|| entity instanceof FireworkRocketEntity
|| entity instanceof ThrownTrident )

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: DoctorDark <doctordark11@gmail.com>
Date: Wed, 16 Mar 2016 02:21:39 -0500
Subject: [PATCH] Configurable end credits
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 10c08ed945f950b9c2a5e308f8caa11955cb0088..067234ed44cae4454acc76b9ebe83ee1394fb913 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -205,4 +205,10 @@ public class PaperWorldConfig {
}
}
}
+
+ public boolean disableEndCredits;
+ private void disableEndCredits() {
+ disableEndCredits = getBoolean("game-mechanics.disable-end-credits", false);
+ log("End credits disabled: " + disableEndCredits);
+ }
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index d4d444b5864073fe86bfc7b5a68344b5aae8c05f..726c5f4ef0ad083d18b23990f1f7b61e3866290c 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -980,6 +980,7 @@ public class ServerPlayer extends Player {
this.unRide();
this.getLevel().removePlayerImmediately(this, Entity.RemovalReason.CHANGED_DIMENSION);
if (!this.wonGame) {
+ if (level.paperConfig.disableEndCredits) this.seenCredits = true; // Paper - Toggle to always disable end credits
this.wonGame = true;
this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, this.seenCredits ? 0.0F : 1.0F));
this.seenCredits = true;

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Iceee <andrew@opticgaming.tv>
Date: Wed, 2 Mar 2016 01:39:52 -0600
Subject: [PATCH] Fix lag from explosions processing dead entities
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index 6929aca0759a090703c1c6ab4daffc069010bfbc..4be483b7a8138514f645909eb3e8ea9975c0f41c 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -208,7 +208,7 @@ public class Explosion {
int i1 = Mth.floor(this.y + (double) f2 + 1.0D);
int j1 = Mth.floor(this.z - (double) f2 - 1.0D);
int k1 = Mth.floor(this.z + (double) f2 + 1.0D);
- List<Entity> list = this.level.getEntities(this.source, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1));
+ List<Entity> list = this.level.getEntities(this.source, new AABB((double) i, (double) l, (double) j1, (double) j, (double) i1, (double) k1), (com.google.common.base.Predicate<Entity>) entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities
Vec3 vec3d = new Vec3(this.x, this.y, this.z);
for (int l1 = 0; l1 < list.size(); ++l1) {

View file

@ -1,148 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Wed, 2 Mar 2016 11:59:48 -0600
Subject: [PATCH] Optimize explosions
The process of determining an entity's exposure from explosions can be
expensive when there are hundreds or more entities in range.
This patch adds a per-tick cache that is used for storing and retrieving
an entity's exposure during an explosion.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 067234ed44cae4454acc76b9ebe83ee1394fb913..73dda3becdf29dac35f4a0ceea070d174c546c8b 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -211,4 +211,10 @@ public class PaperWorldConfig {
disableEndCredits = getBoolean("game-mechanics.disable-end-credits", false);
log("End credits disabled: " + disableEndCredits);
}
+
+ public boolean optimizeExplosions;
+ private void optimizeExplosions() {
+ optimizeExplosions = getBoolean("optimize-explosions", false);
+ log("Optimize explosions: " + optimizeExplosions);
+ }
}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index e26818bd6fb2216ab9b363affe99e4b6c83cca6a..400a59336300b189a1b86621b53817940f9a599e 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1435,6 +1435,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.profiler.pop();
this.profiler.pop();
+ worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions
}
this.profiler.popPush("connection");
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index 4be483b7a8138514f645909eb3e8ea9975c0f41c..318e46932409b83bce923937683619946d876dcb 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -227,7 +227,7 @@ public class Explosion {
d8 /= d11;
d9 /= d11;
d10 /= d11;
- double d12 = (double) Explosion.getSeenPercent(vec3d, entity);
+ double d12 = this.getBlockDensity(vec3d, entity); // Paper - Optimize explosions
double d13 = (1.0D - d7) * d12;
// CraftBukkit start
@@ -465,4 +465,84 @@ public class Explosion {
private BlockInteraction() {}
}
+ // Paper start - Optimize explosions
+ private float getBlockDensity(Vec3 vec3d, Entity entity) {
+ if (!this.level.paperConfig.optimizeExplosions) {
+ return getSeenPercent(vec3d, entity);
+ }
+ CacheKey key = new CacheKey(this, entity.getBoundingBox());
+ Float blockDensity = this.level.explosionDensityCache.get(key);
+ if (blockDensity == null) {
+ blockDensity = getSeenPercent(vec3d, entity);
+ this.level.explosionDensityCache.put(key, blockDensity);
+ }
+
+ return blockDensity;
+ }
+
+ static class CacheKey {
+ private final Level world;
+ private final double posX, posY, posZ;
+ private final double minX, minY, minZ;
+ private final double maxX, maxY, maxZ;
+
+ public CacheKey(Explosion explosion, AABB aabb) {
+ this.world = explosion.level;
+ this.posX = explosion.x;
+ this.posY = explosion.y;
+ this.posZ = explosion.z;
+ this.minX = aabb.minX;
+ this.minY = aabb.minY;
+ this.minZ = aabb.minZ;
+ this.maxX = aabb.maxX;
+ this.maxY = aabb.maxY;
+ this.maxZ = aabb.maxZ;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ CacheKey cacheKey = (CacheKey) o;
+
+ if (Double.compare(cacheKey.posX, posX) != 0) return false;
+ if (Double.compare(cacheKey.posY, posY) != 0) return false;
+ if (Double.compare(cacheKey.posZ, posZ) != 0) return false;
+ if (Double.compare(cacheKey.minX, minX) != 0) return false;
+ if (Double.compare(cacheKey.minY, minY) != 0) return false;
+ if (Double.compare(cacheKey.minZ, minZ) != 0) return false;
+ if (Double.compare(cacheKey.maxX, maxX) != 0) return false;
+ if (Double.compare(cacheKey.maxY, maxY) != 0) return false;
+ if (Double.compare(cacheKey.maxZ, maxZ) != 0) return false;
+ return world.equals(cacheKey.world);
+ }
+
+ @Override
+ public int hashCode() {
+ int result;
+ long temp;
+ result = world.hashCode();
+ temp = Double.doubleToLongBits(posX);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(posY);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(posZ);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(minX);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(minY);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(minZ);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(maxX);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(maxY);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(maxZ);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 8653fa072825c024e0fb620bdada4adc936b0490..7309226b6ee96db7330d712c41157bfde0d03d37 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -151,6 +151,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
+ public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
public CraftWorld getWorld() {
return this.world;

View file

@ -1,69 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 14:48:03 -0600
Subject: [PATCH] Disable explosion knockback
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 73dda3becdf29dac35f4a0ceea070d174c546c8b..1d91adcfa636455bf67c6f7ac7d51baaa6db047f 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -217,4 +217,9 @@ public class PaperWorldConfig {
optimizeExplosions = getBoolean("optimize-explosions", false);
log("Optimize explosions: " + optimizeExplosions);
}
+
+ public boolean disableExplosionKnockback;
+ private void disableExplosionKnockback(){
+ disableExplosionKnockback = getBoolean("disable-explosion-knockback", false);
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index c8e59de21c1fc217068f40fc5c4c87cbfa58d329..91579d3ead3900ed6ff5b050f80ae031b141c24d 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1376,6 +1376,7 @@ public abstract class LivingEntity extends Entity {
}
}
+ boolean knockbackCancelled = level.paperConfig.disableExplosionKnockback && source.isExplosion() && this instanceof net.minecraft.world.entity.player.Player; // Paper - Disable explosion knockback
if (flag1) {
if (flag) {
this.level.broadcastEntityEvent(this, (byte) 29);
@@ -1396,6 +1397,7 @@ public abstract class LivingEntity extends Entity {
b0 = 2;
}
+ if (!knockbackCancelled) // Paper - Disable explosion knockback
this.level.broadcastEntityEvent(this, b0);
}
@@ -1419,6 +1421,7 @@ public abstract class LivingEntity extends Entity {
}
}
+ if (knockbackCancelled) this.level.broadcastEntityEvent(this, (byte) 2); // Paper - Disable explosion knockback
if (this.isDeadOrDying()) {
if (!this.checkTotemDeathProtection(source)) {
SoundEvent soundeffect = this.getDeathSound();
diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java
index 318e46932409b83bce923937683619946d876dcb..afac23f1741baaf2a4ee2729f25a0ddf5f2b9d7d 100644
--- a/src/main/java/net/minecraft/world/level/Explosion.java
+++ b/src/main/java/net/minecraft/world/level/Explosion.java
@@ -262,14 +262,14 @@ public class Explosion {
double d14 = d13;
if (entity instanceof LivingEntity) {
- d14 = ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity) entity, d13);
+ d14 = entity instanceof Player && level.paperConfig.disableExplosionKnockback ? 0 : ProtectionEnchantment.getExplosionKnockbackAfterDampener((LivingEntity) entity, d13); // Paper - Disable explosion knockback
}
entity.setDeltaMovement(entity.getDeltaMovement().add(d8 * d14, d9 * d14, d10 * d14));
if (entity instanceof Player) {
Player entityhuman = (Player) entity;
- if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying)) {
+ if (!entityhuman.isSpectator() && (!entityhuman.isCreative() || !entityhuman.getAbilities().flying) && !level.paperConfig.disableExplosionKnockback) { // Paper - Disable explosion knockback
this.hitPlayers.put(entityhuman, new Vec3(d8 * d13, d9 * d13, d10 * d13));
}
}

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 14:52:43 -0600
Subject: [PATCH] Disable thunder
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 1d91adcfa636455bf67c6f7ac7d51baaa6db047f..a591d52ed44213d7932690136796d3e068b06987 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -222,4 +222,9 @@ public class PaperWorldConfig {
private void disableExplosionKnockback(){
disableExplosionKnockback = getBoolean("disable-explosion-knockback", false);
}
+
+ public boolean disableThunder;
+ private void disableThunder() {
+ disableThunder = getBoolean("disable-thunder", false);
+ }
}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 0eb0229125fd027025b6b44dfceddf626fc05399..9383ba7a6bc91fa73a235e3d94de8a5332ba2924 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -561,7 +561,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
gameprofilerfiller.push("thunder");
BlockPos blockposition;
- if (flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot
+ if (!this.paperConfig.disableThunder && flag && this.isThundering() && this.spigotConfig.thunderChance > 0 && this.random.nextInt(this.spigotConfig.thunderChance) == 0) { // Spigot // Paper - disable thunder
blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
if (this.isRainingAt(blockposition)) {
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 14:57:24 -0600
Subject: [PATCH] Disable ice and snow
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index a591d52ed44213d7932690136796d3e068b06987..18e7960624e4e882677145c3bedd00263a57b051 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -227,4 +227,9 @@ public class PaperWorldConfig {
private void disableThunder() {
disableThunder = getBoolean("disable-thunder", false);
}
+
+ public boolean disableIceAndSnow;
+ private void disableIceAndSnow(){
+ disableIceAndSnow = getBoolean("disable-ice-and-snow", false);
+ }
}
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 9383ba7a6bc91fa73a235e3d94de8a5332ba2924..e330fc198705ff2a4d8503f8710e6424afc9fbbf 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -585,7 +585,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
gameprofilerfiller.popPush("iceandsnow");
- if (this.random.nextInt(16) == 0) {
+ if (!this.paperConfig.disableIceAndSnow && this.random.nextInt(16) == 0) { // Paper - Disable ice and snow
blockposition = this.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.getBlockRandomPos(j, 0, k, 15));
BlockPos blockposition1 = blockposition.below();
Biome biomebase = (Biome) this.getBiome(blockposition).value();

View file

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 15:03:53 -0600
Subject: [PATCH] Configurable mob spawner tick rate
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 18e7960624e4e882677145c3bedd00263a57b051..fcbb0d6cd09a9c80a8725c9cf0c503fa0532f1e3 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -232,4 +232,9 @@ public class PaperWorldConfig {
private void disableIceAndSnow(){
disableIceAndSnow = getBoolean("disable-ice-and-snow", false);
}
+
+ public int mobSpawnerTickRate;
+ private void mobSpawnerTickRate() {
+ mobSpawnerTickRate = getInt("mob-spawner-tick-rate", 1);
+ }
}
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 31bfc0c491c9a4cc6782b6c284121f96972517ea..6aab3df317a9612da9b83284aa6056f0c7cf436c 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -42,6 +42,7 @@ public abstract class BaseSpawner {
public int requiredPlayerRange = 16;
public int spawnRange = 4;
private final Random random = new Random();
+ private int tickDelay = 0; // Paper
public BaseSpawner() {}
@@ -75,13 +76,18 @@ public abstract class BaseSpawner {
}
public void serverTick(ServerLevel world, BlockPos pos) {
+ // Paper start - Configurable mob spawner tick rate
+ if (spawnDelay > 0 && --tickDelay > 0) return;
+ tickDelay = world.paperConfig.mobSpawnerTickRate;
+ if (tickDelay == -1) { return; } // If disabled
+ // Paper end
if (this.isNearPlayer(world, pos)) {
- if (this.spawnDelay == -1) {
+ if (this.spawnDelay < -tickDelay) {
this.delay(world, pos);
}
if (this.spawnDelay > 0) {
- --this.spawnDelay;
+ this.spawnDelay -= tickDelay; // Paper
} else {
boolean flag = false;
@@ -146,8 +152,7 @@ public abstract class BaseSpawner {
((Mob) entity).finalizeSpawn(world, world.getCurrentDifficultyAt(entity.blockPosition()), MobSpawnType.SPAWNER, (SpawnGroupData) null, (CompoundTag) null);
}
// Spigot Start
- if ( entityinsentient.level.spigotConfig.nerfSpawnerMobs )
- {
+ if (entityinsentient.level.spigotConfig.nerfSpawnerMobs) {
entityinsentient.aware = false;
}
// Spigot End

View file

@ -1,48 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Isaac Moore <rmsy@me.com>
Date: Tue, 19 Apr 2016 14:09:31 -0500
Subject: [PATCH] Implement PlayerLocaleChangeEvent
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 726c5f4ef0ad083d18b23990f1f7b61e3866290c..d184c3f8f8f86b783f17d71886c9b43a74482f2a 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1733,7 +1733,7 @@ public class ServerPlayer extends Player {
return s;
}
- public String locale = "en_us"; // CraftBukkit - add, lowercase
+ public String locale = null; // CraftBukkit - add, lowercase // Paper - default to null
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
public void updateOptions(ServerboundClientInformationPacket packet) {
// CraftBukkit start
@@ -1741,9 +1741,10 @@ public class ServerPlayer extends Player {
PlayerChangedMainHandEvent event = new PlayerChangedMainHandEvent(this.getBukkitEntity(), getMainArm() == HumanoidArm.LEFT ? MainHand.LEFT : MainHand.RIGHT);
this.server.server.getPluginManager().callEvent(event);
}
- if (!this.locale.equals(packet.language)) {
+ if (this.locale == null || !this.locale.equals(packet.language)) { // Paper - check for null
PlayerLocaleChangeEvent event = new PlayerLocaleChangeEvent(this.getBukkitEntity(), packet.language);
this.server.server.getPluginManager().callEvent(event);
+ this.server.server.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerLocaleChangeEvent(this.getBukkitEntity(), this.locale, packet.language)); // Paper
}
this.locale = packet.language;
// Paper start
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 6c866e9fc091b8f2b982d5554f381bfed7d669a9..9b03879242d0f299a51cb4e91dd83b68a8ea3b9c 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1961,8 +1961,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public String getLocale() {
- return this.getHandle().locale;
-
+ // Paper start - Locale change event
+ final String locale = this.getHandle().locale;
+ return locale != null ? locale : "en_us";
+ // Paper end
}
// Paper start

View file

@ -1,112 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach@zachbr.io>
Date: Mon, 6 May 2019 01:29:25 -0400
Subject: [PATCH] Per-Player View Distance API placeholders
I hope to look at this more in-depth soon. It appears doable.
However this should not block the update.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index d184c3f8f8f86b783f17d71886c9b43a74482f2a..e8cda0032a6c80e939d24be190507cba006a0280 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -2205,4 +2205,6 @@ public class ServerPlayer extends Player {
return (CraftPlayer) super.getBukkitEntity();
}
// CraftBukkit end
+
+ public final int getViewDistance() { return this.getLevel().getChunkSource().chunkMap.viewDistance - 1; } // Paper - placeholder
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 5476dc1e80093d7684bc238bae102cbb691cec4f..be8b7170f3746e53985286066138781099930934 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1833,6 +1833,37 @@ public class CraftWorld extends CraftRegionAccessor implements World {
return world.spigotConfig.simulationDistance;
}
// Spigot end
+ // Paper start - view distance api
+ @Override
+ public void setViewDistance(int viewDistance) {
+ throw new UnsupportedOperationException(); //TODO
+ }
+
+ @Override
+ public void setSimulationDistance(int simulationDistance) {
+ throw new UnsupportedOperationException(); //TODO
+ }
+
+ @Override
+ public int getNoTickViewDistance() {
+ throw new UnsupportedOperationException(); //TODO
+ }
+
+ @Override
+ public void setNoTickViewDistance(int viewDistance) {
+ throw new UnsupportedOperationException(); //TODO
+ }
+
+ @Override
+ public int getSendViewDistance() {
+ throw new UnsupportedOperationException(); //TODO
+ }
+
+ @Override
+ public void setSendViewDistance(int viewDistance) {
+ throw new UnsupportedOperationException(); //TODO
+ }
+ // Paper end - view distance api
// Spigot start
private final org.bukkit.World.Spigot spigot = new org.bukkit.World.Spigot()
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 9b03879242d0f299a51cb4e91dd83b68a8ea3b9c..34b2b30ba5bf1f163ed647db1ea75e57323fb042 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -405,6 +405,46 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message);
}
}
+
+ @Override
+ public int getViewDistance() {
+ throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
+ }
+
+ @Override
+ public void setViewDistance(int viewDistance) {
+ throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
+ }
+
+ @Override
+ public int getSimulationDistance() {
+ throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
+ }
+
+ @Override
+ public void setSimulationDistance(int simulationDistance) {
+ throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
+ }
+
+ @Override
+ public int getNoTickViewDistance() {
+ throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
+ }
+
+ @Override
+ public void setNoTickViewDistance(int viewDistance) {
+ throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
+ }
+
+ @Override
+ public int getSendViewDistance() {
+ throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
+ }
+
+ @Override
+ public void setSendViewDistance(int viewDistance) {
+ throw new NotImplementedException("Per-Player View Distance APIs need further understanding to properly implement (There are per world view distances though!)"); // TODO
+ }
// Paper end
@Override

View file

@ -1,62 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Byteflux <byte@byteflux.net>
Date: Wed, 2 Mar 2016 23:30:53 -0600
Subject: [PATCH] Add BeaconEffectEvent
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
index ccb9988d5113576d06438acf86a9f451ab0ea157..dca94c75f4531eab3ab788e722363d2065bf4170 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
@@ -41,6 +41,10 @@ import net.minecraft.world.phys.AABB;
import org.bukkit.craftbukkit.potion.CraftPotionUtil;
import org.bukkit.potion.PotionEffect;
// CraftBukkit end
+// Paper start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import com.destroystokyo.paper.event.block.BeaconEffectEvent;
+// Paper end
public class BeaconBlockEntity extends BlockEntity implements MenuProvider {
@@ -272,15 +276,23 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider {
}
}
- private static void applyEffect(List list, MobEffect mobeffectlist, int j, int b0) {
- {
+ private static void applyEffect(List list, MobEffect effects, int i, int b0, boolean isPrimary, BlockPos worldPosition) { // Paper - BeaconEffectEvent
+ if (!list.isEmpty()) { // Paper - BeaconEffectEvent
Iterator iterator = list.iterator();
Player entityhuman;
+ // Paper start - BeaconEffectEvent
+ org.bukkit.block.Block block = ((Player) list.get(0)).level.getWorld().getBlockAt(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ());
+ PotionEffect effect = CraftPotionUtil.toBukkit(new MobEffectInstance(effects, i, b0, true, true));
+ // Paper end
while (iterator.hasNext()) {
- entityhuman = (Player) iterator.next();
- entityhuman.addEffect(new MobEffectInstance(mobeffectlist, j, b0, true, true), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
+ // Paper start - BeaconEffectEvent
+ entityhuman = (ServerPlayer) iterator.next();
+ BeaconEffectEvent event = new BeaconEffectEvent(block, effect, (org.bukkit.entity.Player) entityhuman.getBukkitEntity(), isPrimary);
+ if (CraftEventFactory.callEvent(event).isCancelled()) continue;
+ entityhuman.addEffect(new MobEffectInstance(CraftPotionUtil.fromBukkit(event.getEffect())), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.BEACON);
+ // Paper end
}
}
}
@@ -303,10 +315,10 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider {
int j = BeaconBlockEntity.getLevel(beaconLevel);
List list = BeaconBlockEntity.getHumansInRange(world, pos, beaconLevel);
- BeaconBlockEntity.applyEffect(list, primaryEffect, j, b0);
+ BeaconBlockEntity.applyEffect(list, primaryEffect, j, b0, true, pos); // Paper - BeaconEffectEvent
if (BeaconBlockEntity.hasSecondaryEffect(beaconLevel, primaryEffect, secondaryEffect)) {
- BeaconBlockEntity.applyEffect(list, secondaryEffect, j, 0);
+ BeaconBlockEntity.applyEffect(list, secondaryEffect, j, 0, false, pos); // Paper - BeaconEffectEvent
}
}

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Wed, 2 Mar 2016 23:34:44 -0600
Subject: [PATCH] Configurable container update tick rate
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index fcbb0d6cd09a9c80a8725c9cf0c503fa0532f1e3..156059d4951fa01b10cc36d70cd439037c636e4c 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -237,4 +237,9 @@ public class PaperWorldConfig {
private void mobSpawnerTickRate() {
mobSpawnerTickRate = getInt("mob-spawner-tick-rate", 1);
}
+
+ public int containerUpdateTickRate;
+ private void containerUpdateTickRate() {
+ containerUpdateTickRate = getInt("container-update-tick-rate", 1);
+ }
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index e8cda0032a6c80e939d24be190507cba006a0280..8eb9a96e879a28841fcc338ff5c90f86908414bc 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -219,6 +219,7 @@ public class ServerPlayer extends Player {
private int containerCounter;
public int latency;
public boolean wonGame;
+ private int containerUpdateDelay; // Paper
// CraftBukkit start
public String displayName;
@@ -591,7 +592,12 @@ public class ServerPlayer extends Player {
--this.invulnerableTime;
}
- this.containerMenu.broadcastChanges();
+ // Paper start - Configurable container update tick rate
+ if (--containerUpdateDelay <= 0) {
+ this.containerMenu.broadcastChanges();
+ containerUpdateDelay = level.paperConfig.containerUpdateTickRate;
+ }
+ // Paper end
if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) {
this.closeContainer();
this.containerMenu = this.inventoryMenu;

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com>
Date: Wed, 2 Mar 2016 23:42:37 -0600
Subject: [PATCH] Use UserCache for player heads
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
index 0281a825f5a00f1416405dfe8b1edd9c61fccd93..545074f5f7b109daf17af05fa36a9dc5816f22d4 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
@@ -167,7 +167,13 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
if (name == null) {
this.setProfile(null);
} else {
- this.setProfile(new GameProfile(null, name));
+ // Paper start - Use Online Players Skull
+ GameProfile newProfile = null;
+ net.minecraft.server.level.ServerPlayer player = net.minecraft.server.MinecraftServer.getServer().getPlayerList().getPlayerByName(name);
+ if (player != null) newProfile = player.getGameProfile();
+ if (newProfile == null) newProfile = new GameProfile(null, name);
+ this.setProfile(newProfile);
+ // Paper end
}
return true;

View file

@ -1,21 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Wed, 2 Mar 2016 23:45:17 -0600
Subject: [PATCH] Disable spigot tick limiters
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 7309226b6ee96db7330d712c41157bfde0d03d37..922b234865ff5d64049d634d0356f9a068bc8a8c 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -702,9 +702,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Spigot start
// Iterator iterator = this.blockEntityTickers.iterator();
int tilesThisCycle = 0;
- for (this.tileLimiter.initTick();
- tilesThisCycle < this.blockEntityTickers.size() && (tilesThisCycle % 10 != 0 || this.tileLimiter.shouldContinue());
- this.tileTickPosition++, tilesThisCycle++) {
+ for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters
this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0;
TickingBlockEntity tickingblockentity = (TickingBlockEntity) this.blockEntityTickers.get(tileTickPosition);
// Spigot start

View file

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Steve Anton <anxuiz.nx@gmail.com>
Date: Thu, 3 Mar 2016 00:09:38 -0600
Subject: [PATCH] Add PlayerInitialSpawnEvent
For modifying a player's initial spawn location as they join the server
This is a duplicate API from spigot, so use our duplicate subclass and
improve setPosition to use raw
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 5d7298a045ea827a5530faee62061d0f4ea34e2b..68835bcd519e41808669df51c0a9b04aa21727cb 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -217,7 +217,7 @@ public abstract class PlayerList {
// Spigot start - spawn location event
Player spawnPlayer = player.getBukkitEntity();
- org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new org.spigotmc.event.player.PlayerSpawnLocationEvent(spawnPlayer, spawnPlayer.getLocation());
+ org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new com.destroystokyo.paper.event.player.PlayerInitialSpawnEvent(spawnPlayer, spawnPlayer.getLocation()); // Paper use our duplicate event
this.cserver.getPluginManager().callEvent(ev);
Location loc = ev.getSpawnLocation();
@@ -225,7 +225,10 @@ public abstract class PlayerList {
player.spawnIn(worldserver1);
player.gameMode.setLevel((ServerLevel) player.level);
- player.absMoveTo(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
+ // Paper start - set raw so we aren't fully joined to the world (not added to chunk or world)
+ player.setPosRaw(loc.getX(), loc.getY(), loc.getZ());
+ player.setRot(loc.getYaw(), loc.getPitch());
+ // Paper end
// Spigot end
// CraftBukkit - Moved message to after join

View file

@ -1,37 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 3 Mar 2016 01:13:45 -0600
Subject: [PATCH] Configurable Disabling Cat Chest Detection
Offers a gameplay feature to stop cats from blocking chests
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 156059d4951fa01b10cc36d70cd439037c636e4c..adf5a83fc1b62e55ba4524893f8704ad6cd81e97 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -242,4 +242,9 @@ public class PaperWorldConfig {
private void containerUpdateTickRate() {
containerUpdateTickRate = getInt("container-update-tick-rate", 1);
}
+
+ public boolean disableChestCatDetection;
+ private void disableChestCatDetection() {
+ disableChestCatDetection = getBoolean("game-mechanics.disable-chest-cat-detection", false);
+ }
}
diff --git a/src/main/java/net/minecraft/world/level/block/ChestBlock.java b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
index 306fd5b1893d8a68af2073978bab7e590e936ef5..db726697b00afdee6078849fd224263483349912 100644
--- a/src/main/java/net/minecraft/world/level/block/ChestBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/ChestBlock.java
@@ -362,6 +362,11 @@ public class ChestBlock extends AbstractChestBlock<ChestBlockEntity> implements
}
private static boolean isCatSittingOnChest(LevelAccessor world, BlockPos pos) {
+ // Paper start - Option to disable chest cat detection
+ if (((Level) world).paperConfig.disableChestCatDetection) {
+ return false;
+ }
+ // Paper end
List<Cat> list = world.getEntitiesOfClass(Cat.class, new AABB((double) pos.getX(), (double) (pos.getY() + 1), (double) pos.getZ(), (double) (pos.getX() + 1), (double) (pos.getY() + 2), (double) (pos.getZ() + 1)));
if (!list.isEmpty()) {

View file

@ -1,118 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 3 Mar 2016 01:17:12 -0600
Subject: [PATCH] Ensure commands are not ran async
Plugins calling Player.chat("/foo") or Server.dispatchCommand() could
trigger the server to execute a command while on another thread.
These commands would then process EXPECTING to be on the main thread, leaving to
very hard to trace concurrency issues.
This change will synchronize the command execution back to the main thread, causing a
big slowdown in execution but throwing an exception at same time to raise awareness
that it is happening so that plugin authors can fix their code to stop executing commands async.
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 96c59b0e5ac3d36c8ecd513b64723e7dbe5d9b3a..b85e557972e37566c853e0b4f882719b4d8bb293 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1872,6 +1872,29 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
if (!async && s.startsWith("/")) {
+ // Paper Start
+ if (!org.spigotmc.AsyncCatcher.shuttingDown && !org.bukkit.Bukkit.isPrimaryThread()) {
+ final String fCommandLine = s;
+ LOGGER.error("Command Dispatched Async: " + fCommandLine);
+ LOGGER.error("Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
+ Waitable wait = new Waitable() {
+ @Override
+ protected Object evaluate() {
+ chat(fCommandLine, false);
+ return null;
+ }
+ };
+ server.processQueue.add(wait);
+ try {
+ wait.get();
+ return;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on!
+ } catch (Exception e) {
+ throw new RuntimeException("Exception processing chat command", e.getCause());
+ }
+ }
+ // Paper End
this.handleCommand(s);
} else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) {
// Do nothing, this is coming from a plugin
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 46f895acd74de17784d0c5efc66caf10a8be8686..b6e8bf97d961c5b3fd59c8eab11db5d7cf11fe36 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -857,6 +857,28 @@ public final class CraftServer implements Server {
Validate.notNull(commandLine, "CommandLine cannot be null");
org.spigotmc.AsyncCatcher.catchOp("command dispatch"); // Spigot
+ // Paper Start
+ if (!org.spigotmc.AsyncCatcher.shuttingDown && !Bukkit.isPrimaryThread()) {
+ final CommandSender fSender = sender;
+ final String fCommandLine = commandLine;
+ Bukkit.getLogger().log(Level.SEVERE, "Command Dispatched Async: " + commandLine);
+ Bukkit.getLogger().log(Level.SEVERE, "Please notify author of plugin causing this execution to fix this bug! see: http://bit.ly/1oSiM6C", new Throwable());
+ org.bukkit.craftbukkit.util.Waitable<Boolean> wait = new org.bukkit.craftbukkit.util.Waitable<Boolean>() {
+ @Override
+ protected Boolean evaluate() {
+ return dispatchCommand(fSender, fCommandLine);
+ }
+ };
+ net.minecraft.server.MinecraftServer.getServer().processQueue.add(wait);
+ try {
+ return wait.get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // This is proper habit for java. If we aren't handling it, pass it on!
+ } catch (Exception e) {
+ throw new RuntimeException("Exception processing dispatch command", e.getCause());
+ }
+ }
+ // Paper End
if (this.commandMap.dispatch(sender, commandLine)) {
return true;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
index 19c44daaa407b7c1c7a7ffe56fef8c8814c6d5b2..6a073a9dc44d93eba296a0e18a9c7be8a7881725 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
@@ -13,6 +13,7 @@ public class ServerShutdownThread extends Thread {
public void run() {
try {
org.spigotmc.AsyncCatcher.enabled = false; // Spigot
+ org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
this.server.close();
} finally {
try {
diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java
index 78669fa035b7537ff7e533cf32aaf2995625424f..7585a30e8f063ac2656b5de519b1e9edaceffbc7 100644
--- a/src/main/java/org/spigotmc/AsyncCatcher.java
+++ b/src/main/java/org/spigotmc/AsyncCatcher.java
@@ -6,6 +6,7 @@ public class AsyncCatcher
{
public static boolean enabled = true;
+ public static boolean shuttingDown = false; // Paper
public static void catchOp(String reason)
{
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
index 882e93ad4471e3688f2fcfb1e6f16926786ee5e7..94d8ba376cd1f024b244654cac9bb62bb19e3060 100644
--- a/src/main/java/org/spigotmc/RestartCommand.java
+++ b/src/main/java/org/spigotmc/RestartCommand.java
@@ -43,6 +43,7 @@ public class RestartCommand extends Command
private static void restart(final String restartScript)
{
AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
+ org.spigotmc.AsyncCatcher.shuttingDown = true; // Paper
try
{
String[] split = restartScript.split( " " );

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: vemacs <d@nkmem.es>
Date: Thu, 3 Mar 2016 01:19:22 -0600
Subject: [PATCH] All chunks are slime spawn chunks toggle
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index adf5a83fc1b62e55ba4524893f8704ad6cd81e97..567bad50508870001c3337bf109a407b6b4cde0e 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -247,4 +247,9 @@ public class PaperWorldConfig {
private void disableChestCatDetection() {
disableChestCatDetection = getBoolean("game-mechanics.disable-chest-cat-detection", false);
}
+
+ public boolean allChunksAreSlimeChunks;
+ private void allChunksAreSlimeChunks() {
+ allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", false);
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java
index cee85fcbe061cf70ba9c828372369a4c41f9fbff..990f2e17aad4a1116482b3aa534686cf8dc3669a 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java
@@ -321,7 +321,7 @@ public class Slime extends Mob implements Enemy {
}
ChunkPos chunkcoordintpair = new ChunkPos(pos);
- boolean flag = WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot
+ boolean flag = world.getMinecraftWorld().paperConfig.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper
if (random.nextInt(10) == 0 && flag && pos.getY() < 40) {
return checkMobSpawnRules(type, world, spawnReason, pos, random);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
index d68bb94bf75d04b3f371518558addc645b55d8a4..404bd3389aaa75ca23f04d23ecea9093443c3976 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -219,7 +219,7 @@ public class CraftChunk implements Chunk {
@Override
public boolean isSlimeChunk() {
// 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk
- return WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0;
+ return this.worldServer.paperConfig.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper
}
@Override

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Thu, 3 Mar 2016 02:15:57 -0600
Subject: [PATCH] Expose server CommandMap
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index b6e8bf97d961c5b3fd59c8eab11db5d7cf11fe36..680453b00b7fad402d0311141d82a9f0dd6cce2e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1975,6 +1975,7 @@ public final class CraftServer implements Server {
return this.helpMap;
}
+ @Override // Paper - add override
public SimpleCommandMap getCommandMap() {
return this.commandMap;
}

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Thu, 3 Mar 2016 02:18:39 -0600
Subject: [PATCH] Be a bit more informative in maxHealth exception
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index a6192a7edd94e63c568ca8196e0ed9fa993da6bb..1d3cd79634366718cd354cd2f55c6fc974ad3525 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -99,7 +99,10 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
public void setHealth(double health) {
health = (float) health;
if ((health < 0) || (health > this.getMaxHealth())) {
- throw new IllegalArgumentException("Health must be between 0 and " + this.getMaxHealth() + "(" + health + ")");
+ // Paper - Be more informative
+ throw new IllegalArgumentException("Health must be between 0 and " + getMaxHealth() + ", but was " + health
+ + ". (attribute base value: " + this.getHandle().getAttribute(Attributes.MAX_HEALTH).getBaseValue()
+ + (this instanceof CraftPlayer ? ", player: " + this.getName() + ')' : ')'));
}
// during world generation, we don't want to run logic for dropping items and xp

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 02:33:53 -0600
Subject: [PATCH] Ensure inv drag is in bounds
diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
index fc8c3798643c1a8cf29298f02c8ec057b950a2fc..eecb852e4946c774ad295c53dbd904571262055a 100644
--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -418,7 +418,7 @@ public abstract class AbstractContainerMenu {
this.resetQuickCraft();
}
} else if (this.quickcraftStatus == 1) {
- slot = (Slot) this.slots.get(slotIndex);
+ slot = slotIndex < this.slots.size() ? this.slots.get(slotIndex) : null; // Paper - Ensure drag in bounds
itemstack = this.getCarried();
if (AbstractContainerMenu.canItemQuickReplace(slot, itemstack, true) && slot.mayPlace(itemstack) && (this.quickcraftType == 2 || itemstack.getCount() > this.quickcraftSlots.size()) && this.canDragTo(slot)) {
this.quickcraftSlots.add(slot);

View file

@ -1,176 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com>
Date: Thu, 3 Mar 2016 02:32:10 -0600
Subject: [PATCH] Player Tab List and Title APIs
diff --git a/src/main/java/net/minecraft/network/FriendlyByteBuf.java b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
index 0053474ab7c25de6d86c16e3079feb21f75d1c11..303b877bc467de7c046cc221d061fac841c1d9f3 100644
--- a/src/main/java/net/minecraft/network/FriendlyByteBuf.java
+++ b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
@@ -356,6 +356,11 @@ public class FriendlyByteBuf extends ByteBuf {
public FriendlyByteBuf writeComponent(final net.kyori.adventure.text.Component component) {
return this.writeUtf(PaperAdventure.asJsonString(component, this.adventure$locale), 262144);
}
+
+ @Deprecated
+ public FriendlyByteBuf writeComponent(final net.md_5.bungee.api.chat.BaseComponent[] component) {
+ return this.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(component), 262144);
+ }
// Paper end
public FriendlyByteBuf writeComponent(Component text) {
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java
index c44a276d201fdfa5144d45d319d7761583c60639..f68a1a6dc6add9496e25cb52c318e086e356e2bb 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java
@@ -7,6 +7,7 @@ import net.minecraft.network.protocol.Packet;
public class ClientboundSetSubtitleTextPacket implements Packet<ClientGamePacketListener> {
private final Component text;
public net.kyori.adventure.text.Component adventure$text; // Paper
+ public net.md_5.bungee.api.chat.BaseComponent[] components; // Paper
public ClientboundSetSubtitleTextPacket(Component subtitle) {
this.text = subtitle;
@@ -21,6 +22,8 @@ public class ClientboundSetSubtitleTextPacket implements Packet<ClientGamePacket
// Paper start
if (this.adventure$text != null) {
buf.writeComponent(this.adventure$text);
+ } else if (this.components != null) {
+ buf.writeComponent(this.components);
} else
// Paper end
buf.writeComponent(this.text);
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java
index bd808eb312ade7122973a47f4b96505829511da5..bf0f9cab7c66c089f35b851e799ba4a43420b437 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java
@@ -7,6 +7,7 @@ import net.minecraft.network.protocol.Packet;
public class ClientboundSetTitleTextPacket implements Packet<ClientGamePacketListener> {
private final Component text;
public net.kyori.adventure.text.Component adventure$text; // Paper
+ public net.md_5.bungee.api.chat.BaseComponent[] components; // Paper
public ClientboundSetTitleTextPacket(Component title) {
this.text = title;
@@ -21,6 +22,8 @@ public class ClientboundSetTitleTextPacket implements Packet<ClientGamePacketLis
// Paper start
if (this.adventure$text != null) {
buf.writeComponent(this.adventure$text);
+ } else if (this.components != null) {
+ buf.writeComponent(this.components);
} else
// Paper end
buf.writeComponent(this.text);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 34b2b30ba5bf1f163ed647db1ea75e57323fb042..0f04ae8e52f8dca80cfa71b2162a4c477dc0c4db 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.entity;
+import com.destroystokyo.paper.Title;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
@@ -270,6 +271,100 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
}
+ // Paper start
+ @Override
+ public void setPlayerListHeaderFooter(BaseComponent[] header, BaseComponent[] footer) {
+ if (header != null) {
+ String headerJson = net.md_5.bungee.chat.ComponentSerializer.toString(header);
+ playerListHeader = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(headerJson);
+ } else {
+ playerListHeader = null;
+ }
+
+ if (footer != null) {
+ String footerJson = net.md_5.bungee.chat.ComponentSerializer.toString(footer);
+ playerListFooter = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(footerJson);
+ } else {
+ playerListFooter = null;
+ }
+
+ updatePlayerListHeaderFooter();
+ }
+
+ @Override
+ public void setPlayerListHeaderFooter(BaseComponent header, BaseComponent footer) {
+ this.setPlayerListHeaderFooter(header == null ? null : new BaseComponent[]{header},
+ footer == null ? null : new BaseComponent[]{footer});
+ }
+
+
+ @Override
+ public void setTitleTimes(int fadeInTicks, int stayTicks, int fadeOutTicks) {
+ getHandle().connection.send(new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks));
+ }
+
+ @Override
+ public void setSubtitle(BaseComponent[] subtitle) {
+ final ClientboundSetSubtitleTextPacket packet = new ClientboundSetSubtitleTextPacket((net.minecraft.network.chat.Component) null);
+ packet.components = subtitle;
+ getHandle().connection.send(packet);
+ }
+
+ @Override
+ public void setSubtitle(BaseComponent subtitle) {
+ setSubtitle(new BaseComponent[]{subtitle});
+ }
+
+ @Override
+ public void showTitle(BaseComponent[] title) {
+ final ClientboundSetTitleTextPacket packet = new ClientboundSetTitleTextPacket((net.minecraft.network.chat.Component) null);
+ packet.components = title;
+ getHandle().connection.send(packet);
+ }
+
+ @Override
+ public void showTitle(BaseComponent title) {
+ showTitle(new BaseComponent[]{title});
+ }
+
+ @Override
+ public void showTitle(BaseComponent[] title, BaseComponent[] subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
+ setSubtitle(subtitle);
+ showTitle(title);
+ }
+
+ @Override
+ public void showTitle(BaseComponent title, BaseComponent subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
+ setSubtitle(subtitle);
+ showTitle(title);
+ }
+
+ @Override
+ public void sendTitle(Title title) {
+ Preconditions.checkNotNull(title, "Title is null");
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
+ setSubtitle(title.getSubtitle() == null ? new BaseComponent[0] : title.getSubtitle());
+ showTitle(title.getTitle());
+ }
+
+ @Override
+ public void updateTitle(Title title) {
+ Preconditions.checkNotNull(title, "Title is null");
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
+ if (title.getSubtitle() != null) {
+ setSubtitle(title.getSubtitle());
+ }
+ showTitle(title.getTitle());
+ }
+
+ @Override
+ public void hideTitle() {
+ getHandle().connection.send(new ClientboundClearTitlesPacket(false));
+ }
+ // Paper end
+
@Override
public String getDisplayName() {
if(true) return io.papermc.paper.adventure.DisplayNames.getLegacy(this); // Paper

View file

@ -1,56 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 02:46:17 -0600
Subject: [PATCH] Add configurable portal search radius
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 567bad50508870001c3337bf109a407b6b4cde0e..66dd2ebda5692157e397f7ddafd96a492e53c9e9 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -252,4 +252,13 @@ public class PaperWorldConfig {
private void allChunksAreSlimeChunks() {
allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", false);
}
+
+ public int portalSearchRadius;
+ public int portalCreateRadius;
+ public boolean portalSearchVanillaDimensionScaling;
+ private void portalSearchRadius() {
+ portalSearchRadius = getInt("portal-search-radius", 128);
+ portalCreateRadius = getInt("portal-create-radius", 16);
+ portalSearchVanillaDimensionScaling = getBoolean("portal-search-vanilla-dimension-scaling", true);
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 2f35ce076a468ac260e28ba90ac55f7717ee1b13..4329563bccfefe5d56c12d0fa341f1ffd4ce22a1 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -2911,7 +2911,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
double d0 = DimensionType.getTeleportationScale(this.level.dimensionType(), destination.dimensionType());
BlockPos blockposition = worldborder.clampToBounds(this.getX() * d0, this.getY(), this.getZ() * d0);
// CraftBukkit start
- CraftPortalEvent event = this.callPortalEvent(this, destination, blockposition, PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, flag2 ? 16 : 128, 16);
+ // Paper start
+ int portalSearchRadius = destination.paperConfig.portalSearchRadius;
+ if (level.paperConfig.portalSearchVanillaDimensionScaling && flag2) { // == THE_NETHER
+ portalSearchRadius = (int) (portalSearchRadius / destination.dimensionType().coordinateScale());
+ }
+ // Paper end
+ CraftPortalEvent event = this.callPortalEvent(this, destination, blockposition, PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, portalSearchRadius, destination.paperConfig.portalCreateRadius); // Paper start - configurable portal radius
if (event == null) {
return null;
}
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
index 2f9ce2a5d187bbaf55f2599998aad357dac72ecc..05150fbade1d5a9b3b6de8ad1f5e825f34d1037e 100644
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
@@ -43,7 +43,7 @@ public class PortalForcer {
public Optional<BlockUtil.FoundRectangle> findPortalAround(BlockPos pos, boolean destIsNether, WorldBorder worldBorder) {
// CraftBukkit start
- return this.findPortalAround(pos, worldBorder, destIsNether ? 16 : 128); // Search Radius
+ return this.findPortalAround(pos, worldBorder, destIsNether ? level.paperConfig.portalCreateRadius : level.paperConfig.portalSearchRadius); // Search Radius // Paper - search Radius
}
public Optional<BlockUtil.FoundRectangle> findPortalAround(BlockPos blockposition, WorldBorder worldborder, int i) {

View file

@ -1,88 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 02:48:12 -0600
Subject: [PATCH] Add velocity warnings
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 680453b00b7fad402d0311141d82a9f0dd6cce2e..3341fb3250f2dd06328e7ec8ee2758d7497eaecc 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -279,6 +279,7 @@ public final class CraftServer implements Server {
public boolean ignoreVanillaPermissions = false;
private final List<CraftPlayer> playerView;
public int reloadCount;
+ public static Exception excessiveVelEx; // Paper - Velocity warnings
static {
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index fdbcf4989f72e1604a2841f565adfeebf8d45622..1e0b8314ef388763aa43055909e48778f0d421a3 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -438,10 +438,40 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
public void setVelocity(Vector velocity) {
Preconditions.checkArgument(velocity != null, "velocity");
velocity.checkFinite();
+ // Paper start - Warn server owners when plugins try to set super high velocities
+ if (!(this instanceof org.bukkit.entity.Projectile || this instanceof org.bukkit.entity.Minecart) && isUnsafeVelocity(velocity)) {
+ CraftServer.excessiveVelEx = new Exception("Excessive velocity set detected: tried to set velocity of entity " + entity.getScoreboardName() + " id #" + getEntityId() + " to (" + velocity.getX() + "," + velocity.getY() + "," + velocity.getZ() + ").");
+ }
+ // Paper end
this.entity.setDeltaMovement(CraftVector.toNMS(velocity));
entity.hurtMarked = true;
}
+ // Paper start
+ /**
+ * Checks if the given velocity is not necessarily safe in all situations.
+ * This function returning true does not mean the velocity is dangerous or to be avoided, only that it may be
+ * a detriment to performance on the server.
+ *
+ * It is not to be used as a hard rule of any sort.
+ * Paper only uses it to warn server owners in watchdog crashes.
+ *
+ * @param vel incoming velocity to check
+ * @return if the velocity has the potential to be a performance detriment
+ */
+ private static boolean isUnsafeVelocity(Vector vel) {
+ final double x = vel.getX();
+ final double y = vel.getY();
+ final double z = vel.getZ();
+
+ if (x > 4 || x < -4 || y > 4 || y < -4 || z > 4 || z < -4) {
+ return true;
+ }
+
+ return false;
+ }
+ // Paper end
+
@Override
public double getHeight() {
return this.getHandle().getBbHeight();
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index d5863b0b06384b25eaa33572fa02649795463ed8..2693cc933d746e40d8a47d96c6cb6799f0a2472f 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -80,7 +80,19 @@ public class WatchdogThread extends Thread
log.log( Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed" );
log.log( Level.SEVERE, "near " + net.minecraft.world.level.Level.lastPhysicsProblem );
}
- //
+ // Paper start - Warn in watchdog if an excessive velocity was ever set
+ if ( org.bukkit.craftbukkit.CraftServer.excessiveVelEx != null )
+ {
+ log.log( Level.SEVERE, "------------------------------" );
+ log.log( Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity" );
+ log.log( Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated" );
+ log.log( Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
+ for ( StackTraceElement stack : org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace() )
+ {
+ log.log( Level.SEVERE, "\t\t" + stack );
+ }
+ }
+ // Paper end
log.log( Level.SEVERE, "------------------------------" );
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );

View file

@ -1,44 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Thu, 3 Mar 2016 02:50:31 -0600
Subject: [PATCH] Configurable inter-world teleportation safety
People are able to abuse the way Bukkit handles teleportation across worlds since it provides a built in teleportation
safety check.
To abuse the safety check, players are required to get into a location deemed unsafe by Bukkit e.g. be within a chest
or door block. While they are in this block, they accept a teleport request from a player within a different world. Once
the player teleports, Minecraft will recursively search upwards for a safe location, this could eventually land within a
player's skybase.
Example setup to perform the glitch: http://puu.sh/ng3PC/cf072dcbdb.png
The wanted destination was on top of the emerald block however the player ended on top of the diamond block.
This only is the case if the player is teleporting between worlds.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 66dd2ebda5692157e397f7ddafd96a492e53c9e9..45b51fea6ba4381e4d245d70b5671f6e42c1f718 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -261,4 +261,9 @@ public class PaperWorldConfig {
portalCreateRadius = getInt("portal-create-radius", 16);
portalSearchVanillaDimensionScaling = getBoolean("portal-search-vanilla-dimension-scaling", true);
}
+
+ public boolean disableTeleportationSuffocationCheck;
+ private void disableTeleportationSuffocationCheck() {
+ disableTeleportationSuffocationCheck = getBoolean("disable-teleportation-suffocation-check", false);
+ }
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 0f04ae8e52f8dca80cfa71b2162a4c477dc0c4db..de9dbbff4e0e3d14821d21a1506a6b2d4a8ce3ab 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1034,7 +1034,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
if (fromWorld == toWorld) {
entity.connection.teleport(to);
} else {
- server.getHandle().respawn(entity, toWorld, true, to, true);
+ server.getHandle().respawn(entity, toWorld, true, to, !toWorld.paperConfig.disableTeleportationSuffocationCheck); // Paper
}
return true;
}

View file

@ -1,249 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 03:15:41 -0600
Subject: [PATCH] Add exception reporting event
diff --git a/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..f699ce18ca044f813e194ef2786b7ea853ea86e7
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
@@ -0,0 +1,38 @@
+package com.destroystokyo.paper;
+
+import com.google.common.base.Preconditions;
+import org.bukkit.craftbukkit.scheduler.CraftTask;
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
+import com.destroystokyo.paper.exception.ServerSchedulerException;
+
+/**
+ * Reporting wrapper to catch exceptions not natively
+ */
+public class ServerSchedulerReportingWrapper implements Runnable {
+
+ private final CraftTask internalTask;
+
+ public ServerSchedulerReportingWrapper(CraftTask internalTask) {
+ this.internalTask = Preconditions.checkNotNull(internalTask, "internalTask");
+ }
+
+ @Override
+ public void run() {
+ try {
+ internalTask.run();
+ } catch (RuntimeException e) {
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
+ new ServerExceptionEvent(new ServerSchedulerException(e, internalTask))
+ );
+ throw e;
+ } catch (Throwable t) {
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
+ new ServerExceptionEvent(new ServerSchedulerException(t, internalTask))
+ ); //Do not rethrow, since it is not permitted with Runnable#run
+ }
+ }
+
+ public CraftTask getInternalTask() {
+ return internalTask;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index f9e9e00855627b78e8ff018bf6d52c9787fcffeb..fb8d50dc14e1d23001e184b425bc6ac2f8b0f37e 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -961,6 +961,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
return true;
} catch (Exception exception) {
ChunkMap.LOGGER.error("Failed to save chunk {},{}", new Object[]{chunkcoordintpair.x, chunkcoordintpair.z, exception});
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
return false;
}
}
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
index 7b84b20a4de0d6e95a1d47cb077abd0e00a2336c..b7b98832be6178a2bca534bf974519ede977b282 100644
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
@@ -1,5 +1,6 @@
package net.minecraft.server.players;
+import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
@@ -363,6 +364,7 @@ public class OldUsersConverter {
root = NbtIo.readCompressed(new java.io.FileInputStream(file5));
} catch (Exception exception) {
exception.printStackTrace();
+ ServerInternalException.reportInternalException(exception); // Paper
}
if (root != null) {
@@ -376,6 +378,7 @@ public class OldUsersConverter {
NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
} catch (Exception exception) {
exception.printStackTrace();
+ ServerInternalException.reportInternalException(exception); // Paper
}
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
index 1a9dfd8411bb8affdb3ff4c003433ecab203b004..5e526d0feda11d6b73f71b965aa098e0a79457d1 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
@@ -118,6 +118,7 @@ public class VillageSiege implements CustomSpawner {
entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), MobSpawnType.EVENT, (SpawnGroupData) null, (CompoundTag) null);
} catch (Exception exception) {
VillageSiege.LOGGER.warn("Failed to create zombie for village siege at {}", vec3d, exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
return;
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 922b234865ff5d64049d634d0356f9a068bc8a8c..d923cc91a8f1e71831be8ded1b4818ac3b48fc34 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -1,5 +1,10 @@
package net.minecraft.world.level;
+import co.aikar.timings.Timing;
+import co.aikar.timings.Timings;
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
+import com.destroystokyo.paper.exception.ServerInternalException;
+import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import com.mojang.serialization.Codec;
import java.io.IOException;
@@ -738,6 +743,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Paper start - Prevent tile entity and entity crashes
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
MinecraftServer.LOGGER.error(msg, throwable);
+ getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable)));
entity.discard();
// Paper end
}
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index 2d290d2e17517bc39828e05369ca5bc5ce892c27..fee21a585b95448a5edab70002e9c4ea36a5d989 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -288,6 +288,7 @@ public final class NaturalSpawner {
}
} catch (Exception exception) {
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
return null;
}
}
@@ -400,6 +401,7 @@ public final class NaturalSpawner {
entity = biomesettingsmobs_c.type.create(world.getLevel());
} catch (Exception exception) {
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
continue;
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index ed6203119fe2e4ee47a2d51c84df5b7c236f32da..7a63c26e360fd054bf237df3eeffc466d73d5dfb 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1,6 +1,7 @@
package net.minecraft.world.level.chunk;
import com.google.common.collect.ImmutableList;
+import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.collect.Maps;
import com.google.common.collect.UnmodifiableIterator;
import com.mojang.logging.LogUtils;
@@ -544,10 +545,16 @@ public class LevelChunk extends ChunkAccess {
// CraftBukkit start
} else {
- System.out.println("Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + "," + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
- + " (" + this.getBlockState(blockposition) + ") where there was no entity tile!");
- System.out.println("Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16));
- new Exception().printStackTrace();
+ // Paper start
+ ServerInternalException e = new ServerInternalException(
+ "Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + ","
+ + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
+ + " (" + getBlockState(blockposition) + ") where there was no entity tile!\n" +
+ "Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16) +
+ "\nWorld: " + level.getLevel().dimension().location());
+ e.printStackTrace();
+ ServerInternalException.reportInternalException(e);
+ // Paper end
// CraftBukkit end
}
}
@@ -1027,6 +1034,7 @@ public class LevelChunk extends ChunkAccess {
// Paper start - Prevent tile entity and entity crashes
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
+ net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new ServerInternalException(msg, throwable)));
LevelChunk.this.removeBlockEntity(this.getPos());
// Paper end
// Spigot start
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index d51bafd2f5a763b8a49c835ab74a7cf60caa1ab6..fbf5f01a9a7968194fc85589ca7f9fa328da4881 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -274,6 +274,7 @@ public class RegionFile implements AutoCloseable {
return true;
}
} catch (IOException ioexception) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper
return false;
}
}
@@ -355,6 +356,7 @@ public class RegionFile implements AutoCloseable {
((java.nio.Buffer) bytebuffer).position(5); // CraftBukkit - decompile error
filechannel.write(bytebuffer);
} catch (Throwable throwable) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(throwable); // Paper
if (filechannel != null) {
try {
filechannel.close();
diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
index 5272a718178b5a2cb1df263ce0c5500c92c9ebda..0465b397b628b11a6fc52e3375945c94d68cfdd5 100644
--- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
+++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java
@@ -120,6 +120,7 @@ public class DimensionDataStorage {
pushbackInputStream.close();
} catch (Throwable var15) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(var15); // Paper
try {
fileInputStream.close();
} catch (Throwable var10) {
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
index 07c4d9cd5081378e1b903518f7174fca959cd9e3..dfc2789009fcaa08baa8054bdac915590b8701d6 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -17,6 +17,9 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.logging.Level;
+import com.destroystokyo.paper.ServerSchedulerReportingWrapper;
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
+import com.destroystokyo.paper.exception.ServerSchedulerException;
import org.apache.commons.lang.Validate;
import org.bukkit.plugin.IllegalPluginAccessException;
import org.bukkit.plugin.Plugin;
@@ -434,6 +437,8 @@ public class CraftScheduler implements BukkitScheduler {
msg,
throwable);
}
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(
+ new ServerExceptionEvent(new ServerSchedulerException(msg, throwable, task)));
// Paper end
} finally {
this.currentTask = null;
@@ -441,7 +446,7 @@ public class CraftScheduler implements BukkitScheduler {
this.parsePending();
} else {
this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass()));
- this.executor.execute(task);
+ this.executor.execute(new ServerSchedulerReportingWrapper(task)); // Paper
// We don't need to parse pending
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
}

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Tue, 8 Mar 2016 18:28:43 -0800
Subject: [PATCH] Don't nest if we don't need to when cerealising text
components
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundChatPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundChatPacket.java
index f4f52e43852d2b0b56770c3f747a655a3a6dd683..8b0d452b12d5eca1f92e2cdf014118e215407b31 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundChatPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundChatPacket.java
@@ -36,7 +36,14 @@ public class ClientboundChatPacket implements Packet<ClientGamePacketListener> {
// Paper end
// Spigot start
if (this.components != null) {
- buf.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(components));
+ // buf.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(components)); // Paper - comment, replaced with below
+ // Paper start - don't nest if we don't need to so that we can preserve formatting
+ if (this.components.length == 1) {
+ buf.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(this.components[0]));
+ } else {
+ buf.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(this.components));
+ }
+ // Paper end
} else {
buf.writeComponent(this.message);
}

View file

@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 8 Mar 2016 23:25:45 -0500
Subject: [PATCH] Disable Scoreboards for non players by default
Entities collision is checking for scoreboards setting.
This is very heavy to do map lookups for every collision to check
this setting.
So avoid looking up scoreboards and short circuit to the "not on a team"
logic which is most likely to be true.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 45b51fea6ba4381e4d245d70b5671f6e42c1f718..397995fe4c360d837282535b9b7aaf7f3d93f85f 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -266,4 +266,9 @@ public class PaperWorldConfig {
private void disableTeleportationSuffocationCheck() {
disableTeleportationSuffocationCheck = getBoolean("disable-teleportation-suffocation-check", false);
}
+
+ public boolean nonPlayerEntitiesOnScoreboards = false;
+ private void nonPlayerEntitiesOnScoreboards() {
+ nonPlayerEntitiesOnScoreboards = getBoolean("allow-non-player-entities-on-scoreboards", false);
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 4329563bccfefe5d56c12d0fa341f1ffd4ce22a1..79dddb060d967303be70b690df83c3b2a2b1f67e 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -2551,6 +2551,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
@Nullable
public Team getTeam() {
+ if (!this.level.paperConfig.nonPlayerEntitiesOnScoreboards && !(this instanceof Player)) { return null; } // Paper
return this.level.getScoreboard().getPlayersTeam(this.getScoreboardName());
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 91579d3ead3900ed6ff5b050f80ae031b141c24d..cb7cccee34e897195d0a258ba6623b75e797ee7c 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -800,6 +800,7 @@ public abstract class LivingEntity extends Entity {
if (nbt.contains("Team", 8)) {
String s = nbt.getString("Team");
PlayerTeam scoreboardteam = this.level.getScoreboard().getPlayerTeam(s);
+ if (!level.paperConfig.nonPlayerEntitiesOnScoreboards && !(this instanceof net.minecraft.world.entity.player.Player)) { scoreboardteam = null; } // Paper
boolean flag = scoreboardteam != null && this.level.getScoreboard().addPlayerToTeam(this.getStringUUID(), scoreboardteam);
if (!flag) {

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: mrapple <tony@oc.tc>
Date: Sun, 25 Nov 2012 13:43:39 -0600
Subject: [PATCH] Add methods for working with arrows stuck in living entities
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 1d3cd79634366718cd354cd2f55c6fc974ad3525..b65d44780c7e6e1e2e8724df838d1aa54edcc30a 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -717,4 +717,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
this.getHandle().persistentInvisibility = invisible;
this.getHandle().setSharedFlag(5, invisible);
}
+
+ // Paper start
+ @Override
+ public int getArrowsStuck() {
+ return getHandle().getArrowCount();
+ }
+
+ @Override
+ public void setArrowsStuck(int arrows) {
+ getHandle().setArrowCount(arrows);
+ }
+ // Paper end
}

View file

@ -1,51 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 4 Mar 2013 23:46:10 -0500
Subject: [PATCH] Chunk Save Reattempt
We commonly have "Stream Closed" errors on chunk saving, so this code should re-try to save the chunk in the event of failure and hopefully prevent rollbacks.
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index fbf5f01a9a7968194fc85589ca7f9fa328da4881..2d74ab966a1291895b6248a67a31fe4802b3773f 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -274,7 +274,7 @@ public class RegionFile implements AutoCloseable {
return true;
}
} catch (IOException ioexception) {
- com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(ioexception); // Paper - we want the upper try/catch to retry this
return false;
}
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 8ba1c073387fa21a20bd42a873ec3cc314eae64e..eaf22cec54b512e0f57606f50627d5fe9b39bd5c 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -131,6 +131,7 @@ public class RegionFileStorage implements AutoCloseable {
protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException {
RegionFile regionfile = this.getRegionFile(pos, false); // CraftBukkit
+ int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper
if (nbt == null) {
regionfile.clear(pos);
@@ -156,6 +157,18 @@ public class RegionFileStorage implements AutoCloseable {
}
}
+ // Paper start
+ return;
+ } catch (Exception ex) {
+ laste = ex;
+ }
+ }
+
+ if (laste != null) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(laste);
+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk", laste);
+ }
+ // Paper end
}
public void close() throws IOException {