13
0
geforkt von Mirrors/Paper

reformat spigot package

Dieser Commit ist enthalten in:
Lulu13022002 2024-12-16 19:22:36 +01:00
Ursprung 7d29c678f7
Commit 57c683647f
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 491C8F0B8ACDEB01
11 geänderte Dateien mit 559 neuen und 1376 gelöschten Zeilen

Datei anzeigen

@ -2,17 +2,14 @@ package org.spigotmc;
import net.minecraft.server.MinecraftServer;
public class AsyncCatcher
{
public class AsyncCatcher {
public static boolean enabled = true;
public static void catchOp(String reason)
{
if ( AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread )
{
MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); // Paper
throw new IllegalStateException( "Asynchronous " + reason + "!" );
public static void catchOp(String reason) {
if (AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().serverThread) {
MinecraftServer.LOGGER.error("Thread {} failed main thread check: {}", Thread.currentThread().getName(), reason, new Throwable()); // Paper
throw new IllegalStateException("Asynchronous " + reason + "!");
}
}
}

Datei anzeigen

@ -5,35 +5,30 @@ import java.io.IOException;
import java.io.InputStream;
import net.minecraft.nbt.NbtAccounter;
public class LimitStream extends FilterInputStream
{
public class LimitStream extends FilterInputStream {
private final NbtAccounter limit;
public LimitStream(InputStream is, NbtAccounter limit)
{
super( is );
public LimitStream(InputStream is, NbtAccounter limit) {
super(is);
this.limit = limit;
}
@Override
public int read() throws IOException
{
this.limit.accountBytes( 1 );
public int read() throws IOException {
this.limit.accountBytes(1);
return super.read();
}
@Override
public int read(byte[] b) throws IOException
{
this.limit.accountBytes( b.length );
return super.read( b );
public int read(byte[] b) throws IOException {
this.limit.accountBytes(b.length);
return super.read(b);
}
@Override
public int read(byte[] b, int off, int len) throws IOException
{
this.limit.accountBytes( len );
return super.read( b, off, len );
public int read(byte[] b, int off, int len) throws IOException {
this.limit.accountBytes(len);
return super.read(b, off, len);
}
}

Datei anzeigen

@ -1,641 +0,0 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package org.spigotmc;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import net.minecraft.server.MinecraftServer;
import org.bukkit.Bukkit;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
/**
* <p> The metrics class obtains data about a plugin and submits statistics about it to the metrics backend. </p> <p>
* Public methods provided by this class: </p>
* <code>
* Graph createGraph(String name); <br/>
* void addCustomData(BukkitMetrics.Plotter plotter); <br/>
* void start(); <br/>
* </code>
*/
public class Metrics {
/**
* The current revision number
*/
private static final int REVISION = 6;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "https://mcstats.spigotmc.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/report/%s";
/**
* The separator to use for custom data. This MUST NOT change unless you are hosting your own version of metrics and
* want to change it.
*/
private static final String CUSTOM_DATA_SEPARATOR = "~~";
/**
* Interval of time to ping (in minutes)
*/
private static final int PING_INTERVAL = 10;
/**
* All of the custom graphs to submit to metrics
*/
private final Set<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
/**
* The default graph, used for addCustomData when you don't want a specific graph
*/
private final Graph defaultGraph = new Graph("Default");
/**
* The plugin configuration file
*/
private final YamlConfiguration configuration;
/**
* The plugin configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
/**
* Lock for synchronization
*/
private final Object optOutLock = new Object();
/**
* The scheduled task
*/
private volatile Timer task = null;
public Metrics() throws IOException {
// load the config
this.configurationFile = this.getConfigFile();
this.configuration = YamlConfiguration.loadConfiguration(this.configurationFile);
// add some defaults
this.configuration.addDefault("opt-out", false);
this.configuration.addDefault("guid", UUID.randomUUID().toString());
this.configuration.addDefault("debug", false);
// Do we need to create the file?
if (this.configuration.get("guid", null) == null) {
this.configuration.options().header("http://mcstats.org").copyDefaults(true);
this.configuration.save(this.configurationFile);
}
// Load the guid then
this.guid = this.configuration.getString("guid");
this.debug = this.configuration.getBoolean("debug", false);
}
/**
* Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics
* website. Plotters can be added to the graph object returned.
*
* @param name The name of the graph
* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
*/
public Graph createGraph(final String name) {
if (name == null) {
throw new IllegalArgumentException("Graph name cannot be null");
}
// Construct the graph object
final Graph graph = new Graph(name);
// Now we can add our graph
this.graphs.add(graph);
// and return back
return graph;
}
/**
* Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend
*
* @param graph The name of the graph
*/
public void addGraph(final Graph graph) {
if (graph == null) {
throw new IllegalArgumentException("Graph cannot be null");
}
this.graphs.add(graph);
}
/**
* Adds a custom data plotter to the default graph
*
* @param plotter The plotter to use to plot custom data
*/
public void addCustomData(final Plotter plotter) {
if (plotter == null) {
throw new IllegalArgumentException("Plotter cannot be null");
}
// Add the plotter to the graph o/
this.defaultGraph.addPlotter(plotter);
// Ensure the default graph is included in the submitted graphs
this.graphs.add(this.defaultGraph);
}
/**
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
* ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
synchronized (this.optOutLock) {
// Did we opt out?
if (this.isOptOut()) {
return false;
}
// Is metrics already running?
if (this.task != null) {
return true;
}
// Begin hitting the server with glorious data
this.task = new Timer("Spigot Metrics Thread", true);
this.task.scheduleAtFixedRate(new TimerTask() {
private boolean firstPost = true;
public void run() {
try {
// This has to be synchronized or it can collide with the disable method.
synchronized (Metrics.this.optOutLock) {
// Disable Task, if it is running and the server owner decided to opt-out
if (Metrics.this.isOptOut() && Metrics.this.task != null) {
Metrics.this.task.cancel();
Metrics.this.task = null;
// Tell all plotters to stop gathering information.
for (Graph graph : Metrics.this.graphs) {
graph.onOptOut();
}
}
}
// We use the inverse of firstPost because if it is the first time we are posting,
// it is not a interval ping, so it evaluates to FALSE
// Each time thereafter it will evaluate to TRUE, i.e PING!
Metrics.this.postPlugin(!this.firstPost);
// After the first post we set firstPost to false
// Each post thereafter will be a ping
this.firstPost = false;
} catch (IOException e) {
if (Metrics.this.debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
}
}
}
}, 0, TimeUnit.MINUTES.toMillis(Metrics.PING_INTERVAL));
return true;
}
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
synchronized (this.optOutLock) {
try {
// Reload the metrics file
this.configuration.load(this.getConfigFile());
} catch (IOException ex) {
if (this.debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
} catch (InvalidConfigurationException ex) {
if (this.debug) {
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
}
return true;
}
return this.configuration.getBoolean("opt-out", false);
}
}
/**
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (this.optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (this.isOptOut()) {
this.configuration.set("opt-out", false);
this.configuration.save(this.configurationFile);
}
// Enable Task, if it is not running
if (this.task == null) {
this.start();
}
}
}
/**
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
*
* @throws java.io.IOException
*/
public void disable() throws IOException {
// This has to be synchronized or it can collide with the check in the task.
synchronized (this.optOutLock) {
// Check if the server owner has already set opt-out, if not, set it.
if (!this.isOptOut()) {
this.configuration.set("opt-out", true);
this.configuration.save(this.configurationFile);
}
// Disable Task, if it is running
if (this.task != null) {
this.task.cancel();
this.task = null;
}
}
}
/**
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
// I believe the easiest way to get the base folder (e.g craftbukkit set via -P) for plugins to use
// is to abuse the plugin object we already have
// plugin.getDataFolder() => base/plugins/PluginA/
// pluginsFolder => base/plugins/
// The base is not necessarily relative to the startup directory.
// File pluginsFolder = plugin.getDataFolder().getParentFile();
// return => base/plugins/PluginMetrics/config.yml
return new File(new File((File) MinecraftServer.getServer().options.valueOf("plugins"), "PluginMetrics"), "config.yml");
}
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(final boolean isPing) throws IOException {
// Server software specific section
String pluginName = "Spigot";
boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE if online mode is enabled
String pluginVersion = (Metrics.class.getPackage().getImplementationVersion() != null) ? Metrics.class.getPackage().getImplementationVersion() : "unknown";
String serverVersion = Bukkit.getVersion();
int playersOnline = Bukkit.getServer().getOnlinePlayers().size();
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
final StringBuilder data = new StringBuilder();
// The plugin's description file containg all of the plugin data such as name, version, author, etc
data.append(Metrics.encode("guid")).append('=').append(Metrics.encode(this.guid));
Metrics.encodeDataPair(data, "version", pluginVersion);
Metrics.encodeDataPair(data, "server", serverVersion);
Metrics.encodeDataPair(data, "players", Integer.toString(playersOnline));
Metrics.encodeDataPair(data, "revision", String.valueOf(Metrics.REVISION));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
Metrics.encodeDataPair(data, "osname", osname);
Metrics.encodeDataPair(data, "osarch", osarch);
Metrics.encodeDataPair(data, "osversion", osversion);
Metrics.encodeDataPair(data, "cores", Integer.toString(coreCount));
Metrics.encodeDataPair(data, "online-mode", Boolean.toString(onlineMode));
Metrics.encodeDataPair(data, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
Metrics.encodeDataPair(data, "ping", "true");
}
// Acquire a lock on the graphs, which lets us make the assumption we also lock everything
// inside of the graph (e.g plotters)
synchronized (this.graphs) {
final Iterator<Graph> iter = this.graphs.iterator();
while (iter.hasNext()) {
final Graph graph = iter.next();
for (Plotter plotter : graph.getPlotters()) {
// The key name to send to the metrics server
// The format is C-GRAPHNAME-PLOTTERNAME where separator - is defined at the top
// Legacy (R4) submitters use the format Custom%s, or CustomPLOTTERNAME
final String key = String.format("C%s%s%s%s", Metrics.CUSTOM_DATA_SEPARATOR, graph.getName(), Metrics.CUSTOM_DATA_SEPARATOR, plotter.getColumnName());
// The value to send, which for the foreseeable future is just the string
// value of plotter.getValue()
final String value = Integer.toString(plotter.getValue());
// Add it to the http post data :)
Metrics.encodeDataPair(data, key, value);
}
}
}
// Create the url
URL url = new URL(Metrics.BASE_URL + String.format(Metrics.REPORT_URL, Metrics.encode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (this.isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
connection.setDoOutput(true);
// Write the data
final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(data.toString());
writer.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
final String response = reader.readLine();
// close resources
writer.close();
reader.close();
if (response == null || response.startsWith("ERR")) {
throw new IOException(response); //Throw the exception
} else {
// Is this the first update this hour?
if (response.contains("OK This is your first update this hour")) {
synchronized (this.graphs) {
final Iterator<Graph> iter = this.graphs.iterator();
while (iter.hasNext()) {
final Graph graph = iter.next();
for (Plotter plotter : graph.getPlotters()) {
plotter.reset();
}
}
}
}
}
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* <p>Encode a key/value data pair to be used in a HTTP post request. This INCLUDES a & so the first key/value pair
* MUST be included manually, e.g:</p>
* <code>
* StringBuffer data = new StringBuffer();
* data.append(encode("guid")).append('=').append(encode(guid));
* encodeDataPair(data, "version", description.getVersion());
* </code>
*
* @param buffer the stringbuilder to append the data pair onto
* @param key the key value
* @param value the value
*/
private static void encodeDataPair(final StringBuilder buffer, final String key, final String value) throws UnsupportedEncodingException {
buffer.append('&').append(Metrics.encode(key)).append('=').append(Metrics.encode(value));
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String encode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
/**
* Represents a custom graph on the website
*/
public static class Graph {
/**
* The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is
* rejected
*/
private final String name;
/**
* The set of plotters that are contained within this graph
*/
private final Set<Plotter> plotters = new LinkedHashSet<Plotter>();
private Graph(final String name) {
this.name = name;
}
/**
* Gets the graph's name
*
* @return the Graph's name
*/
public String getName() {
return this.name;
}
/**
* Add a plotter to the graph, which will be used to plot entries
*
* @param plotter the plotter to add to the graph
*/
public void addPlotter(final Plotter plotter) {
this.plotters.add(plotter);
}
/**
* Remove a plotter from the graph
*
* @param plotter the plotter to remove from the graph
*/
public void removePlotter(final Plotter plotter) {
this.plotters.remove(plotter);
}
/**
* Gets an <b>unmodifiable</b> set of the plotter objects in the graph
*
* @return an unmodifiable {@link java.util.Set} of the plotter objects
*/
public Set<Plotter> getPlotters() {
return Collections.unmodifiableSet(this.plotters);
}
@Override
public int hashCode() {
return this.name.hashCode();
}
@Override
public boolean equals(final Object object) {
if (!(object instanceof Graph)) {
return false;
}
final Graph graph = (Graph) object;
return graph.name.equals(this.name);
}
/**
* Called when the server owner decides to opt-out of BukkitMetrics while the server is running.
*/
protected void onOptOut() {
}
}
/**
* Interface used to collect custom data for a plugin
*/
public abstract static class Plotter {
/**
* The plot's name
*/
private final String name;
/**
* Construct a plotter with the default plot name
*/
public Plotter() {
this("Default");
}
/**
* Construct a plotter with a specific plot name
*
* @param name the name of the plotter to use, which will show up on the website
*/
public Plotter(final String name) {
this.name = name;
}
/**
* Get the current value for the plotted point. Since this function defers to an external function it may or may
* not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called
* from any thread so care should be taken when accessing resources that need to be synchronized.
*
* @return the current value for the point to be plotted.
*/
public abstract int getValue();
/**
* Get the column name for the plotted point
*
* @return the plotted point's column name
*/
public String getColumnName() {
return this.name;
}
/**
* Called after the website graphs have been updated
*/
public void reset() {
}
@Override
public int hashCode() {
return this.getColumnName().hashCode();
}
@Override
public boolean equals(final Object object) {
if (!(object instanceof Plotter)) {
return false;
}
final Plotter plotter = (Plotter) object;
return plotter.name.equals(this.name) && plotter.getValue() == this.getValue();
}
}
}

Datei anzeigen

@ -1,115 +1,85 @@
package org.spigotmc;
import java.io.File;
import java.util.List;
import java.util.Locale;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.util.CraftChatMessage;
public class RestartCommand extends Command
{
public class RestartCommand extends Command {
public RestartCommand(String name)
{
super( name );
public RestartCommand(String name) {
super(name);
this.description = "Restarts the server";
this.usageMessage = "/restart";
this.setPermission( "bukkit.command.restart" );
this.setPermission("bukkit.command.restart");
}
@Override
public boolean execute(CommandSender sender, String currentAlias, String[] args)
{
if ( this.testPermission( sender ) )
{
MinecraftServer.getServer().processQueue.add( new Runnable()
{
@Override
public void run()
{
RestartCommand.restart();
}
} );
public boolean execute(CommandSender sender, String currentAlias, String[] args) {
if (this.testPermission(sender)) {
MinecraftServer.getServer().processQueue.add(RestartCommand::restart);
}
return true;
}
public static void restart()
{
RestartCommand.restart( SpigotConfig.restartScript );
public static void restart() {
RestartCommand.restart(SpigotConfig.restartScript);
}
private static void restart(final String restartScript)
{
AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
try
{
private static void restart(final String restartScript) {
AsyncCatcher.enabled = false; // Disable async catcher in case it interferes with us
try {
// Paper - extract method and cleanup
boolean isRestarting = addShutdownHook( restartScript );
if ( isRestarting )
{
System.out.println( "Attempting to restart with " + SpigotConfig.restartScript );
} else
{
System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." );
boolean isRestarting = addShutdownHook(restartScript);
if (isRestarting) {
System.out.println("Attempting to restart with " + SpigotConfig.restartScript);
} else {
System.out.println("Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server.");
}
// Stop the watchdog
WatchdogThread.doStop();
shutdownServer( isRestarting );
shutdownServer(isRestarting);
// Paper end
} catch ( Exception ex )
{
} catch (Exception ex) {
ex.printStackTrace();
}
}
// Paper start - sync copied from above with minor changes, async added
private static void shutdownServer(boolean isRestarting)
{
if ( MinecraftServer.getServer().isSameThread() )
{
private static void shutdownServer(boolean isRestarting) {
if (MinecraftServer.getServer().isSameThread()) {
// Kick all players
for ( ServerPlayer p : com.google.common.collect.ImmutableList.copyOf( MinecraftServer.getServer().getPlayerList().players ) )
{
p.connection.disconnect( CraftChatMessage.fromStringOrEmpty( SpigotConfig.restartMessage, true ), org.bukkit.event.player.PlayerKickEvent.Cause.RESTART_COMMAND); // Paper - kick event reason (cause is never used))
for (ServerPlayer p : com.google.common.collect.ImmutableList.copyOf(MinecraftServer.getServer().getPlayerList().players)) {
p.connection.disconnect(CraftChatMessage.fromStringOrEmpty(SpigotConfig.restartMessage, true), org.bukkit.event.player.PlayerKickEvent.Cause.RESTART_COMMAND); // Paper - kick event reason (cause is never used)
}
// Give the socket a chance to send the packets
try
{
Thread.sleep( 100 );
} catch ( InterruptedException ex )
{
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
closeSocket();
// Actually shutdown
try
{
try {
MinecraftServer.getServer().close(); // calls stop()
} catch ( Throwable t )
{
} catch (Throwable t) {
}
// Actually stop the JVM
System.exit( 0 );
} else
{
System.exit(0);
} else {
// Mark the server to shutdown at the end of the tick
MinecraftServer.getServer().safeShutdown( false, isRestarting );
MinecraftServer.getServer().safeShutdown(false, isRestarting);
// wait 10 seconds to see if we're actually going to try shutdown
try
{
Thread.sleep( 10000 );
}
catch (InterruptedException ignored)
{
}
try {
Thread.sleep(10000);
} catch (InterruptedException ignored) {}
// Check if we've actually hit a state where the server is going to safely shutdown
// if we have, let the server stop as usual
@ -117,63 +87,46 @@ public class RestartCommand extends Command
// If the server hasn't stopped by now, assume worse case and kill
closeSocket();
System.exit( 0 );
System.exit(0);
}
}
// Paper end
// Paper - Split from moved code
private static void closeSocket()
{
private static void closeSocket() {
// Close the socket so we can rebind with the new process
MinecraftServer.getServer().getConnection().stop();
// Give time for it to kick in
try
{
Thread.sleep( 100 );
} catch ( InterruptedException ex )
{
}
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {}
}
// Paper end
// Paper start - copied from above and modified to return if the hook registered
private static boolean addShutdownHook(String restartScript)
{
String[] split = restartScript.split( " " );
if ( split.length > 0 && new File( split[0] ).isFile() )
{
Thread shutdownHook = new Thread()
{
@Override
public void run()
{
try
{
String os = System.getProperty( "os.name" ).toLowerCase(java.util.Locale.ENGLISH);
if ( os.contains( "win" ) )
{
Runtime.getRuntime().exec( "cmd /c start " + restartScript );
} else
{
Runtime.getRuntime().exec( "sh " + restartScript );
}
} catch ( Exception e )
{
e.printStackTrace();
private static boolean addShutdownHook(String restartScript) {
String[] split = restartScript.split(" ");
if (split.length > 0 && new File(split[0]).isFile()) {
Thread shutdownHook = new Thread(() -> {
try {
String os = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
if (os.contains("win")) {
Runtime.getRuntime().exec("cmd /c start " + restartScript);
} else {
Runtime.getRuntime().exec("sh " + restartScript);
}
} catch (Exception e) {
e.printStackTrace();
}
};
});
shutdownHook.setDaemon( true );
Runtime.getRuntime().addShutdownHook( shutdownHook );
shutdownHook.setDaemon(true);
Runtime.getRuntime().addShutdownHook(shutdownHook);
return true;
} else
{
} else {
return false;
}
}
// Paper end
}

Datei anzeigen

@ -1,12 +1,14 @@
package org.spigotmc;
import java.io.File;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import static net.kyori.adventure.text.Component.text;
public class SpigotCommand extends Command {
public SpigotCommand(String name) {
@ -21,13 +23,17 @@ public class SpigotCommand extends Command {
if (!this.testPermission(sender)) return true;
if (args.length != 1) {
sender.sendMessage(ChatColor.RED + "Usage: " + this.usageMessage);
sender.sendMessage(text("Usage: " + this.usageMessage, NamedTextColor.RED));
return false;
}
if (args[0].equals("reload")) {
Command.broadcastCommandMessage(sender, ChatColor.RED + "Please note that this command is not supported and may cause issues.");
Command.broadcastCommandMessage(sender, ChatColor.RED + "If you encounter any issues please use the /stop command to restart your server.");
Command.broadcastCommandMessage(sender, text().color(NamedTextColor.RED)
.append(text("Please note that this command is not supported and may cause issues."))
.appendNewline()
.append(text("If you encounter any issues please use the /stop command to restart your server."))
.build()
);
MinecraftServer console = MinecraftServer.getServer();
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings"));
@ -36,7 +42,7 @@ public class SpigotCommand extends Command {
}
console.server.reloadCount++;
Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Reload complete.");
Command.broadcastCommandMessage(sender, text("Reload complete.", NamedTextColor.GREEN));
}
return true;

Datei anzeigen

@ -28,360 +28,289 @@ import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
public class SpigotConfig
{
public class SpigotConfig {
private static File CONFIG_FILE;
private static final String HEADER = "This is the main configuration file for Spigot.\n"
+ "As you can see, there's tons to configure. Some options may impact gameplay, so use\n"
+ "with caution, and make sure you know what each option does before configuring.\n"
+ "For a reference for any variable inside this file, check out the Spigot wiki at\n"
+ "http://www.spigotmc.org/wiki/spigot-configuration/\n"
+ "\n"
+ "If you need help with the configuration or have any questions related to Spigot,\n"
+ "join us at the Discord or drop by our forums and leave a post.\n"
+ "\n"
+ "Discord: https://www.spigotmc.org/go/discord\n"
+ "Forums: http://www.spigotmc.org/\n";
private static final String HEADER = """
This is the main configuration file for Spigot.
As you can see, there's tons to configure. Some options may impact gameplay, so use
with caution, and make sure you know what each option does before configuring.
For a reference for any variable inside this file, check out the Spigot wiki at
http://www.spigotmc.org/wiki/spigot-configuration/
If you need help with the configuration or have any questions related to Spigot,
join us at the Discord or drop by our forums and leave a post.
Discord: https://www.spigotmc.org/go/discord
Forums: http://www.spigotmc.org/
""";
/*========================================================================*/
public static YamlConfiguration config;
static int version;
static Map<String, Command> commands;
/*========================================================================*/
private static Metrics metrics;
public static void init(File configFile)
{
public static void init(File configFile) {
SpigotConfig.CONFIG_FILE = configFile;
SpigotConfig.config = new YamlConfiguration();
try
{
SpigotConfig.config.load( SpigotConfig.CONFIG_FILE );
} catch ( IOException ex )
{
} catch ( InvalidConfigurationException ex )
{
Bukkit.getLogger().log( Level.SEVERE, "Could not load spigot.yml, please correct your syntax errors", ex );
throw Throwables.propagate( ex );
try {
SpigotConfig.config.load(SpigotConfig.CONFIG_FILE);
} catch (IOException ignored) {
} catch (InvalidConfigurationException ex) {
Bukkit.getLogger().log(Level.SEVERE, "Could not load spigot.yml, please correct your syntax errors", ex);
throw Throwables.propagate(ex);
}
SpigotConfig.config.options().header( SpigotConfig.HEADER );
SpigotConfig.config.options().copyDefaults( true );
SpigotConfig.config.options().header(SpigotConfig.HEADER);
SpigotConfig.config.options().copyDefaults(true);
SpigotConfig.commands = new HashMap<String, Command>();
SpigotConfig.commands.put( "spigot", new SpigotCommand( "spigot" ) );
SpigotConfig.commands = new HashMap<>();
SpigotConfig.commands.put("spigot", new SpigotCommand("spigot"));
SpigotConfig.version = SpigotConfig.getInt( "config-version", 12 );
SpigotConfig.set( "config-version", 12 );
SpigotConfig.readConfig( SpigotConfig.class, null );
SpigotConfig.version = SpigotConfig.getInt("config-version", 12);
SpigotConfig.set("config-version", 12);
SpigotConfig.readConfig(SpigotConfig.class, null);
}
public static void registerCommands()
{
for ( Map.Entry<String, Command> entry : SpigotConfig.commands.entrySet() )
{
MinecraftServer.getServer().server.getCommandMap().register( entry.getKey(), "Spigot", entry.getValue() );
public static void registerCommands() {
for (Map.Entry<String, Command> entry : SpigotConfig.commands.entrySet()) {
MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Spigot", entry.getValue());
}
/* // Paper - Replace with our own
if ( SpigotConfig.metrics == null )
{
try
{
SpigotConfig.metrics = new Metrics();
SpigotConfig.metrics.start();
} catch ( IOException ex )
{
Bukkit.getServer().getLogger().log( Level.SEVERE, "Could not start metrics service", ex );
}
}
*/ // Paper end
}
public static void readConfig(Class<?> clazz, Object instance) // Paper - package-private -> public
{
for ( Method method : clazz.getDeclaredMethods() )
{
if ( Modifier.isPrivate( method.getModifiers() ) )
{
if ( method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE )
{
try
{
method.setAccessible( true );
method.invoke( instance );
} catch ( InvocationTargetException ex )
{
throw Throwables.propagate( ex.getCause() );
} catch ( Exception ex )
{
Bukkit.getLogger().log( Level.SEVERE, "Error invoking " + method, ex );
public static void readConfig(Class<?> clazz, Object instance) { // Paper - package-private -> public
for (Method method : clazz.getDeclaredMethods()) {
if (Modifier.isPrivate(method.getModifiers())) {
if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) {
try {
method.setAccessible(true);
method.invoke(instance);
} catch (InvocationTargetException ex) {
throw Throwables.propagate(ex.getCause());
} catch (Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex);
}
}
}
}
try
{
SpigotConfig.config.save( SpigotConfig.CONFIG_FILE );
} catch ( IOException ex )
{
Bukkit.getLogger().log( Level.SEVERE, "Could not save " + SpigotConfig.CONFIG_FILE, ex );
try {
SpigotConfig.config.save(SpigotConfig.CONFIG_FILE);
} catch (IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, "Could not save " + SpigotConfig.CONFIG_FILE, ex);
}
}
private static void set(String path, Object val)
{
SpigotConfig.config.set( path, val );
private static void set(String path, Object val) {
SpigotConfig.config.set(path, val);
}
private static boolean getBoolean(String path, boolean def)
{
SpigotConfig.config.addDefault( path, def );
return SpigotConfig.config.getBoolean( path, SpigotConfig.config.getBoolean( path ) );
private static boolean getBoolean(String path, boolean def) {
SpigotConfig.config.addDefault(path, def);
return SpigotConfig.config.getBoolean(path, SpigotConfig.config.getBoolean(path));
}
private static int getInt(String path, int def)
{
SpigotConfig.config.addDefault( path, def );
return SpigotConfig.config.getInt( path, SpigotConfig.config.getInt( path ) );
private static int getInt(String path, int def) {
SpigotConfig.config.addDefault(path, def);
return SpigotConfig.config.getInt(path, SpigotConfig.config.getInt(path));
}
private static <T> List getList(String path, T def)
{
SpigotConfig.config.addDefault( path, def );
return (List<T>) SpigotConfig.config.getList( path, SpigotConfig.config.getList( path ) );
private static <T> List getList(String path, T def) {
SpigotConfig.config.addDefault(path, def);
return (List<T>) SpigotConfig.config.getList(path, SpigotConfig.config.getList(path));
}
private static String getString(String path, String def)
{
SpigotConfig.config.addDefault( path, def );
return SpigotConfig.config.getString( path, SpigotConfig.config.getString( path ) );
private static String getString(String path, String def) {
SpigotConfig.config.addDefault(path, def);
return SpigotConfig.config.getString(path, SpigotConfig.config.getString(path));
}
private static double getDouble(String path, double def)
{
SpigotConfig.config.addDefault( path, def );
return SpigotConfig.config.getDouble( path, SpigotConfig.config.getDouble( path ) );
private static double getDouble(String path, double def) {
SpigotConfig.config.addDefault(path, def);
return SpigotConfig.config.getDouble(path, SpigotConfig.config.getDouble(path));
}
public static boolean logCommands;
private static void logCommands()
{
SpigotConfig.logCommands = SpigotConfig.getBoolean( "commands.log", true );
private static void logCommands() {
SpigotConfig.logCommands = SpigotConfig.getBoolean("commands.log", true);
}
public static int tabComplete;
public static boolean sendNamespaced;
private static void tabComplete()
{
if ( SpigotConfig.version < 6 )
{
boolean oldValue = SpigotConfig.getBoolean( "commands.tab-complete", true );
if ( oldValue )
{
SpigotConfig.set( "commands.tab-complete", 0 );
} else
{
SpigotConfig.set( "commands.tab-complete", -1 );
private static void tabComplete() {
if (SpigotConfig.version < 6) {
boolean oldValue = SpigotConfig.getBoolean("commands.tab-complete", true);
if (oldValue) {
SpigotConfig.set("commands.tab-complete", 0);
} else {
SpigotConfig.set("commands.tab-complete", -1);
}
}
SpigotConfig.tabComplete = SpigotConfig.getInt( "commands.tab-complete", 0 );
SpigotConfig.sendNamespaced = SpigotConfig.getBoolean( "commands.send-namespaced", true );
SpigotConfig.tabComplete = SpigotConfig.getInt("commands.tab-complete", 0);
SpigotConfig.sendNamespaced = SpigotConfig.getBoolean("commands.send-namespaced", true);
}
public static String whitelistMessage;
public static String unknownCommandMessage;
public static String serverFullMessage;
public static String outdatedClientMessage = "Outdated client! Please use {0}";
public static String outdatedServerMessage = "Outdated server! I\'m still on {0}";
private static String transform(String s)
{
return ChatColor.translateAlternateColorCodes( '&', s ).replaceAll( "\\\\n", "\n" );
public static String outdatedServerMessage = "Outdated server! I'm still on {0}";
private static String transform(String s) {
return ChatColor.translateAlternateColorCodes('&', s).replaceAll("\\\\n", "\n");
}
private static void messages()
{
if (SpigotConfig.version < 8)
{
SpigotConfig.set( "messages.outdated-client", SpigotConfig.outdatedClientMessage );
SpigotConfig.set( "messages.outdated-server", SpigotConfig.outdatedServerMessage );
private static void messages() {
if (SpigotConfig.version < 8) {
SpigotConfig.set("messages.outdated-client", SpigotConfig.outdatedClientMessage);
SpigotConfig.set("messages.outdated-server", SpigotConfig.outdatedServerMessage);
}
SpigotConfig.whitelistMessage = SpigotConfig.transform( SpigotConfig.getString( "messages.whitelist", "You are not whitelisted on this server!" ) );
SpigotConfig.unknownCommandMessage = SpigotConfig.transform( SpigotConfig.getString( "messages.unknown-command", "Unknown command. Type \"/help\" for help." ) );
SpigotConfig.serverFullMessage = SpigotConfig.transform( SpigotConfig.getString( "messages.server-full", "The server is full!" ) );
SpigotConfig.outdatedClientMessage = SpigotConfig.transform( SpigotConfig.getString( "messages.outdated-client", SpigotConfig.outdatedClientMessage ) );
SpigotConfig.outdatedServerMessage = SpigotConfig.transform( SpigotConfig.getString( "messages.outdated-server", SpigotConfig.outdatedServerMessage ) );
SpigotConfig.whitelistMessage = SpigotConfig.transform(SpigotConfig.getString("messages.whitelist", "You are not whitelisted on this server!"));
SpigotConfig.unknownCommandMessage = SpigotConfig.transform(SpigotConfig.getString("messages.unknown-command", "Unknown command. Type \"/help\" for help."));
SpigotConfig.serverFullMessage = SpigotConfig.transform(SpigotConfig.getString("messages.server-full", "The server is full!"));
SpigotConfig.outdatedClientMessage = SpigotConfig.transform(SpigotConfig.getString("messages.outdated-client", SpigotConfig.outdatedClientMessage));
SpigotConfig.outdatedServerMessage = SpigotConfig.transform(SpigotConfig.getString("messages.outdated-server", SpigotConfig.outdatedServerMessage));
}
public static int timeoutTime = 60;
public static boolean restartOnCrash = true;
public static String restartScript = "./start.sh";
public static String restartMessage;
private static void watchdog()
{
SpigotConfig.timeoutTime = SpigotConfig.getInt( "settings.timeout-time", SpigotConfig.timeoutTime );
SpigotConfig.restartOnCrash = SpigotConfig.getBoolean( "settings.restart-on-crash", SpigotConfig.restartOnCrash );
SpigotConfig.restartScript = SpigotConfig.getString( "settings.restart-script", SpigotConfig.restartScript );
SpigotConfig.restartMessage = SpigotConfig.transform( SpigotConfig.getString( "messages.restart", "Server is restarting" ) );
SpigotConfig.commands.put( "restart", new RestartCommand( "restart" ) );
// WatchdogThread.doStart( SpigotConfig.timeoutTime, SpigotConfig.restartOnCrash ); // Paper - moved to after paper config initialization
private static void watchdog() {
SpigotConfig.timeoutTime = SpigotConfig.getInt("settings.timeout-time", SpigotConfig.timeoutTime);
SpigotConfig.restartOnCrash = SpigotConfig.getBoolean("settings.restart-on-crash", SpigotConfig.restartOnCrash);
SpigotConfig.restartScript = SpigotConfig.getString("settings.restart-script", SpigotConfig.restartScript);
SpigotConfig.restartMessage = SpigotConfig.transform(SpigotConfig.getString("messages.restart", "Server is restarting"));
SpigotConfig.commands.put("restart", new RestartCommand("restart"));
}
public static boolean bungee;
private static void bungee() {
if ( SpigotConfig.version < 4 )
{
SpigotConfig.set( "settings.bungeecord", false );
System.out.println( "Outdated config, disabling BungeeCord support!" );
if (SpigotConfig.version < 4) {
SpigotConfig.set("settings.bungeecord", false);
System.out.println("Outdated config, disabling BungeeCord support!");
}
SpigotConfig.bungee = SpigotConfig.getBoolean( "settings.bungeecord", false );
SpigotConfig.bungee = SpigotConfig.getBoolean("settings.bungeecord", false);
}
private static void nettyThreads()
{
int count = SpigotConfig.getInt( "settings.netty-threads", 4 );
System.setProperty( "io.netty.eventLoopThreads", Integer.toString( count ) );
Bukkit.getLogger().log( Level.INFO, "Using {0} threads for Netty based IO", count );
private static void nettyThreads() {
int count = SpigotConfig.getInt("settings.netty-threads", 4);
System.setProperty("io.netty.eventLoopThreads", Integer.toString(count));
Bukkit.getLogger().log(Level.INFO, "Using {0} threads for Netty based IO", count);
}
public static boolean disableStatSaving;
public static Map<ResourceLocation, Integer> forcedStats = new HashMap<>();
private static void stats()
{
SpigotConfig.disableStatSaving = SpigotConfig.getBoolean( "stats.disable-saving", false );
if ( !SpigotConfig.config.contains( "stats.forced-stats" ) ) {
SpigotConfig.config.createSection( "stats.forced-stats" );
private static void stats() {
SpigotConfig.disableStatSaving = SpigotConfig.getBoolean("stats.disable-saving", false);
if (!SpigotConfig.config.contains("stats.forced-stats")) {
SpigotConfig.config.createSection("stats.forced-stats");
}
ConfigurationSection section = SpigotConfig.config.getConfigurationSection( "stats.forced-stats" );
for ( String name : section.getKeys( true ) )
{
if ( section.isInt( name ) )
{
try
{
ResourceLocation key = ResourceLocation.parse( name );
if ( BuiltInRegistries.CUSTOM_STAT.get( key ) == null )
{
ConfigurationSection section = SpigotConfig.config.getConfigurationSection("stats.forced-stats");
for (String name : section.getKeys(true)) {
if (section.isInt(name)) {
try {
ResourceLocation key = ResourceLocation.parse(name);
if (BuiltInRegistries.CUSTOM_STAT.get(key) == null) {
Bukkit.getLogger().log(Level.WARNING, "Ignoring non existent stats.forced-stats " + name);
continue;
}
SpigotConfig.forcedStats.put( key, section.getInt( name ) );
} catch (Exception ex)
{
SpigotConfig.forcedStats.put(key, section.getInt(name));
} catch (Exception ex) {
Bukkit.getLogger().log(Level.WARNING, "Ignoring invalid stats.forced-stats " + name);
}
}
}
}
private static void tpsCommand()
{
SpigotConfig.commands.put( "tps", new TicksPerSecondCommand( "tps" ) );
private static void tpsCommand() {
SpigotConfig.commands.put("tps", new TicksPerSecondCommand("tps"));
}
public static int playerSample;
private static void playerSample()
{
SpigotConfig.playerSample = Math.max( SpigotConfig.getInt( "settings.sample-count", 12 ), 0 ); // Paper - Avoid negative counts
Bukkit.getLogger().log( Level.INFO, "Server Ping Player Sample Count: {0}", playerSample ); // Paper - Use logger
private static void playerSample() {
SpigotConfig.playerSample = Math.max(SpigotConfig.getInt("settings.sample-count", 12), 0); // Paper - Avoid negative counts
Bukkit.getLogger().log(Level.INFO, "Server Ping Player Sample Count: {0}", playerSample); // Paper - Use logger
}
public static int playerShuffle;
private static void playerShuffle()
{
SpigotConfig.playerShuffle = SpigotConfig.getInt( "settings.player-shuffle", 0 );
private static void playerShuffle() {
SpigotConfig.playerShuffle = SpigotConfig.getInt("settings.player-shuffle", 0);
}
public static List<String> spamExclusions;
private static void spamExclusions()
{
SpigotConfig.spamExclusions = SpigotConfig.getList( "commands.spam-exclusions", Arrays.asList( new String[]
{
"/skill"
} ) );
private static void spamExclusions() {
SpigotConfig.spamExclusions = SpigotConfig.getList("commands.spam-exclusions", List.of("/skill"));
}
public static boolean silentCommandBlocks;
private static void silentCommandBlocks()
{
SpigotConfig.silentCommandBlocks = SpigotConfig.getBoolean( "commands.silent-commandblock-console", false );
private static void silentCommandBlocks() {
SpigotConfig.silentCommandBlocks = SpigotConfig.getBoolean("commands.silent-commandblock-console", false);
}
public static Set<String> replaceCommands;
private static void replaceCommands()
{
if ( SpigotConfig.config.contains( "replace-commands" ) )
{
SpigotConfig.set( "commands.replace-commands", SpigotConfig.config.getStringList( "replace-commands" ) );
SpigotConfig.config.set( "replace-commands", null );
private static void replaceCommands() {
if (SpigotConfig.config.contains("replace-commands")) {
SpigotConfig.set("commands.replace-commands", SpigotConfig.config.getStringList("replace-commands"));
SpigotConfig.config.set("replace-commands", null);
}
SpigotConfig.replaceCommands = new HashSet<String>( (List<String>) SpigotConfig.getList( "commands.replace-commands",
Arrays.asList( "setblock", "summon", "testforblock", "tellraw" ) ) );
SpigotConfig.replaceCommands = new HashSet<>(SpigotConfig.getList("commands.replace-commands",
Arrays.asList("setblock", "summon", "testforblock", "tellraw")));
}
public static int userCacheCap;
private static void userCacheCap()
{
SpigotConfig.userCacheCap = SpigotConfig.getInt( "settings.user-cache-size", 1000 );
private static void userCacheCap() {
SpigotConfig.userCacheCap = SpigotConfig.getInt("settings.user-cache-size", 1000);
}
public static boolean saveUserCacheOnStopOnly;
private static void saveUserCacheOnStopOnly()
{
SpigotConfig.saveUserCacheOnStopOnly = SpigotConfig.getBoolean( "settings.save-user-cache-on-stop-only", false );
private static void saveUserCacheOnStopOnly() {
SpigotConfig.saveUserCacheOnStopOnly = SpigotConfig.getBoolean("settings.save-user-cache-on-stop-only", false);
}
public static double movedWronglyThreshold;
private static void movedWronglyThreshold()
{
SpigotConfig.movedWronglyThreshold = SpigotConfig.getDouble( "settings.moved-wrongly-threshold", 0.0625D );
private static void movedWronglyThreshold() {
SpigotConfig.movedWronglyThreshold = SpigotConfig.getDouble("settings.moved-wrongly-threshold", 0.0625D);
}
public static double movedTooQuicklyMultiplier;
private static void movedTooQuicklyMultiplier()
{
SpigotConfig.movedTooQuicklyMultiplier = SpigotConfig.getDouble( "settings.moved-too-quickly-multiplier", 10.0D );
private static void movedTooQuicklyMultiplier() {
SpigotConfig.movedTooQuicklyMultiplier = SpigotConfig.getDouble("settings.moved-too-quickly-multiplier", 10.0D);
}
public static double maxAbsorption = 2048;
public static double maxHealth = 2048;
public static double movementSpeed = 2048;
public static double maxHealth = 1024;
public static double movementSpeed = 1024;
public static double attackDamage = 2048;
private static void attributeMaxes()
{
SpigotConfig.maxAbsorption = SpigotConfig.getDouble( "settings.attribute.maxAbsorption.max", SpigotConfig.maxAbsorption );
( (RangedAttribute) Attributes.MAX_ABSORPTION.value() ).maxValue = SpigotConfig.maxAbsorption;
SpigotConfig.maxHealth = SpigotConfig.getDouble( "settings.attribute.maxHealth.max", SpigotConfig.maxHealth );
( (RangedAttribute) Attributes.MAX_HEALTH.value() ).maxValue = SpigotConfig.maxHealth;
SpigotConfig.movementSpeed = SpigotConfig.getDouble( "settings.attribute.movementSpeed.max", SpigotConfig.movementSpeed );
( (RangedAttribute) Attributes.MOVEMENT_SPEED.value() ).maxValue = SpigotConfig.movementSpeed;
SpigotConfig.attackDamage = SpigotConfig.getDouble( "settings.attribute.attackDamage.max", SpigotConfig.attackDamage );
( (RangedAttribute) Attributes.ATTACK_DAMAGE.value() ).maxValue = SpigotConfig.attackDamage;
private static void attributeMaxes() {
SpigotConfig.maxAbsorption = SpigotConfig.getDouble("settings.attribute.maxAbsorption.max", SpigotConfig.maxAbsorption);
((RangedAttribute) Attributes.MAX_ABSORPTION.value()).maxValue = SpigotConfig.maxAbsorption;
SpigotConfig.maxHealth = SpigotConfig.getDouble("settings.attribute.maxHealth.max", SpigotConfig.maxHealth);
((RangedAttribute) Attributes.MAX_HEALTH.value()).maxValue = SpigotConfig.maxHealth;
SpigotConfig.movementSpeed = SpigotConfig.getDouble("settings.attribute.movementSpeed.max", SpigotConfig.movementSpeed);
((RangedAttribute) Attributes.MOVEMENT_SPEED.value()).maxValue = SpigotConfig.movementSpeed;
SpigotConfig.attackDamage = SpigotConfig.getDouble("settings.attribute.attackDamage.max", SpigotConfig.attackDamage);
((RangedAttribute) Attributes.ATTACK_DAMAGE.value()).maxValue = SpigotConfig.attackDamage;
}
public static boolean debug;
private static void debug()
{
SpigotConfig.debug = SpigotConfig.getBoolean( "settings.debug", false );
private static void debug() {
SpigotConfig.debug = SpigotConfig.getBoolean("settings.debug", false);
if ( SpigotConfig.debug && !LogManager.getRootLogger().isTraceEnabled() )
{
if (SpigotConfig.debug && !LogManager.getRootLogger().isTraceEnabled()) {
// Enable debug logging
LoggerContext ctx = (LoggerContext) LogManager.getContext( false );
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration conf = ctx.getConfiguration();
conf.getLoggerConfig( LogManager.ROOT_LOGGER_NAME ).setLevel( org.apache.logging.log4j.Level.ALL );
ctx.updateLoggers( conf );
conf.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).setLevel(org.apache.logging.log4j.Level.ALL);
ctx.updateLoggers(conf);
}
if ( LogManager.getRootLogger().isTraceEnabled() )
{
Bukkit.getLogger().info( "Debug logging is enabled" );
} else
{
// Bukkit.getLogger().info( "Debug logging is disabled" ); // Paper - Don't log if debug logging isn't enabled.
if (LogManager.getRootLogger().isTraceEnabled()) {
Bukkit.getLogger().info("Debug logging is enabled");
}
}
@ -389,7 +318,7 @@ public class SpigotConfig
public static List<String> disabledAdvancements;
private static void disabledAdvancements() {
SpigotConfig.disableAdvancementSaving = SpigotConfig.getBoolean("advancements.disable-saving", false);
SpigotConfig.disabledAdvancements = SpigotConfig.getList("advancements.disabled", Arrays.asList(new String[]{"minecraft:story/disabled"}));
SpigotConfig.disabledAdvancements = SpigotConfig.getList("advancements.disabled", List.of("minecraft:story/disabled"));
}
public static boolean logVillagerDeaths;

Datei anzeigen

@ -4,86 +4,73 @@ import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
public class SpigotWorldConfig
{
public class SpigotWorldConfig {
private final String worldName;
private final YamlConfiguration config;
private boolean verbose;
public SpigotWorldConfig(String worldName)
{
public SpigotWorldConfig(String worldName) {
this.worldName = worldName;
this.config = SpigotConfig.config;
this.init();
}
public void init()
{
this.verbose = this.getBoolean( "verbose", false ); // Paper
public void init() {
this.verbose = this.getBoolean("verbose", false); // Paper
this.log( "-------- World Settings For [" + this.worldName + "] --------" );
SpigotConfig.readConfig( SpigotWorldConfig.class, this );
this.log("-------- World Settings For [" + this.worldName + "] --------");
SpigotConfig.readConfig(SpigotWorldConfig.class, this);
}
private void log(String s)
{
if ( this.verbose )
{
Bukkit.getLogger().info( s );
private void log(String s) {
if (this.verbose) {
Bukkit.getLogger().info(s);
}
}
private void set(String path, Object val)
{
this.config.set( "world-settings.default." + path, val );
private void set(String path, Object val) {
this.config.set("world-settings.default." + path, val);
}
public boolean getBoolean(String path, boolean def)
{
this.config.addDefault( "world-settings.default." + path, def );
return this.config.getBoolean( "world-settings." + this.worldName + "." + path, this.config.getBoolean( "world-settings.default." + path ) );
public boolean getBoolean(String path, boolean def) {
this.config.addDefault("world-settings.default." + path, def);
return this.config.getBoolean("world-settings." + this.worldName + "." + path, this.config.getBoolean("world-settings.default." + path));
}
public double getDouble(String path, double def)
{
this.config.addDefault( "world-settings.default." + path, def );
return this.config.getDouble( "world-settings." + this.worldName + "." + path, this.config.getDouble( "world-settings.default." + path ) );
public double getDouble(String path, double def) {
this.config.addDefault("world-settings.default." + path, def);
return this.config.getDouble("world-settings." + this.worldName + "." + path, this.config.getDouble("world-settings.default." + path));
}
public int getInt(String path)
{
return this.config.getInt( "world-settings." + this.worldName + "." + path );
public int getInt(String path) {
return this.config.getInt("world-settings." + this.worldName + "." + path);
}
public int getInt(String path, int def)
{
public int getInt(String path, int def) {
// Paper start - get int without setting default
return this.getInt(path, def, true);
}
public int getInt(String path, int def, boolean setDef)
{
if (setDef) this.config.addDefault( "world-settings.default." + path, def );
return this.config.getInt( "world-settings." + this.worldName + "." + path, this.config.getInt( "world-settings.default." + path, def ) );
public int getInt(String path, int def, boolean setDef) {
if (setDef) this.config.addDefault("world-settings.default." + path, def);
return this.config.getInt("world-settings." + this.worldName + "." + path, this.config.getInt("world-settings.default." + path, def));
// Paper end
}
public <T> List getList(String path, T def)
{
this.config.addDefault( "world-settings.default." + path, def );
return (List<T>) this.config.getList( "world-settings." + this.worldName + "." + path, this.config.getList( "world-settings.default." + path ) );
public <T> List getList(String path, T def) {
this.config.addDefault("world-settings.default." + path, def);
return (List<T>) this.config.getList("world-settings." + this.worldName + "." + path, this.config.getList("world-settings.default." + path));
}
public String getString(String path, String def)
{
this.config.addDefault( "world-settings.default." + path, def );
return this.config.getString( "world-settings." + this.worldName + "." + path, this.config.getString( "world-settings.default." + path ) );
public String getString(String path, String def) {
this.config.addDefault("world-settings.default." + path, def);
return this.config.getString("world-settings." + this.worldName + "." + path, this.config.getString("world-settings.default." + path));
}
private Object get(String path, Object def)
{
this.config.addDefault( "world-settings.default." + path, def );
return this.config.get( "world-settings." + this.worldName + "." + path, this.config.get( "world-settings.default." + path ) );
private Object get(String path, Object def) {
this.config.addDefault("world-settings.default." + path, def);
return this.config.get("world-settings." + this.worldName + "." + path, this.config.get("world-settings.default." + path));
}
// Crop growth rates
@ -109,102 +96,92 @@ public class SpigotWorldConfig
public int caveVinesModifier;
public int glowBerryModifier; // Paper
public int pitcherPlantModifier; // Paper
private int getAndValidateGrowth(String crop)
{
int modifier = this.getInt( "growth." + crop.toLowerCase(java.util.Locale.ENGLISH) + "-modifier", 100 );
if ( modifier == 0 )
{
this.log( "Cannot set " + crop + " growth to zero, defaulting to 100" );
private int getAndValidateGrowth(String crop) {
int modifier = this.getInt("growth." + crop.toLowerCase(java.util.Locale.ENGLISH) + "-modifier", 100);
if (modifier == 0) {
this.log("Cannot set " + crop + " growth to zero, defaulting to 100");
modifier = 100;
}
this.log( crop + " Growth Modifier: " + modifier + "%" );
this.log(crop + " Growth Modifier: " + modifier + "%");
return modifier;
}
private void growthModifiers()
{
this.cactusModifier = this.getAndValidateGrowth( "Cactus" );
this.caneModifier = this.getAndValidateGrowth( "Cane" );
this.melonModifier = this.getAndValidateGrowth( "Melon" );
this.mushroomModifier = this.getAndValidateGrowth( "Mushroom" );
this.pumpkinModifier = this.getAndValidateGrowth( "Pumpkin" );
this.saplingModifier = this.getAndValidateGrowth( "Sapling" );
this.beetrootModifier = this.getAndValidateGrowth( "Beetroot" );
this.carrotModifier = this.getAndValidateGrowth( "Carrot" );
this.potatoModifier = this.getAndValidateGrowth( "Potato" );
private void growthModifiers() {
this.cactusModifier = this.getAndValidateGrowth("Cactus");
this.caneModifier = this.getAndValidateGrowth("Cane");
this.melonModifier = this.getAndValidateGrowth("Melon");
this.mushroomModifier = this.getAndValidateGrowth("Mushroom");
this.pumpkinModifier = this.getAndValidateGrowth("Pumpkin");
this.saplingModifier = this.getAndValidateGrowth("Sapling");
this.beetrootModifier = this.getAndValidateGrowth("Beetroot");
this.carrotModifier = this.getAndValidateGrowth("Carrot");
this.potatoModifier = this.getAndValidateGrowth("Potato");
this.torchFlowerModifier = this.getAndValidateGrowth("TorchFlower"); // Paper
this.wheatModifier = this.getAndValidateGrowth( "Wheat" );
this.wartModifier = this.getAndValidateGrowth( "NetherWart" );
this.vineModifier = this.getAndValidateGrowth( "Vine" );
this.cocoaModifier = this.getAndValidateGrowth( "Cocoa" );
this.bambooModifier = this.getAndValidateGrowth( "Bamboo" );
this.sweetBerryModifier = this.getAndValidateGrowth( "SweetBerry" );
this.kelpModifier = this.getAndValidateGrowth( "Kelp" );
this.twistingVinesModifier = this.getAndValidateGrowth( "TwistingVines" );
this.weepingVinesModifier = this.getAndValidateGrowth( "WeepingVines" );
this.caveVinesModifier = this.getAndValidateGrowth( "CaveVines" );
this.wheatModifier = this.getAndValidateGrowth("Wheat");
this.wartModifier = this.getAndValidateGrowth("NetherWart");
this.vineModifier = this.getAndValidateGrowth("Vine");
this.cocoaModifier = this.getAndValidateGrowth("Cocoa");
this.bambooModifier = this.getAndValidateGrowth("Bamboo");
this.sweetBerryModifier = this.getAndValidateGrowth("SweetBerry");
this.kelpModifier = this.getAndValidateGrowth("Kelp");
this.twistingVinesModifier = this.getAndValidateGrowth("TwistingVines");
this.weepingVinesModifier = this.getAndValidateGrowth("WeepingVines");
this.caveVinesModifier = this.getAndValidateGrowth("CaveVines");
this.glowBerryModifier = this.getAndValidateGrowth("GlowBerry"); // Paper
this.pitcherPlantModifier = this.getAndValidateGrowth("PitcherPlant"); // Paper
}
public double itemMerge;
private void itemMerge()
{
this.itemMerge = this.getDouble("merge-radius.item", 0.5 );
this.log( "Item Merge Radius: " + this.itemMerge );
private void itemMerge() {
this.itemMerge = this.getDouble("merge-radius.item", 0.5);
this.log("Item Merge Radius: " + this.itemMerge);
}
public double expMerge;
private void expMerge()
{
this.expMerge = this.getDouble("merge-radius.exp", -1 );
this.log( "Experience Merge Radius: " + this.expMerge );
private void expMerge() {
this.expMerge = this.getDouble("merge-radius.exp", -1);
this.log("Experience Merge Radius: " + this.expMerge);
}
public int viewDistance;
private void viewDistance()
{
if ( SpigotConfig.version < 12 )
{
this.set( "view-distance", null );
private void viewDistance() {
if (SpigotConfig.version < 12) {
this.set("view-distance", null);
}
Object viewDistanceObject = this.get( "view-distance", "default" );
this.viewDistance = ( viewDistanceObject ) instanceof Number ? ( (Number) viewDistanceObject ).intValue() : -1;
if ( this.viewDistance <= 0 )
{
Object viewDistanceObject = this.get("view-distance", "default");
this.viewDistance = (viewDistanceObject) instanceof Number ? ((Number) viewDistanceObject).intValue() : -1;
if (this.viewDistance <= 0) {
this.viewDistance = Bukkit.getViewDistance();
}
this.viewDistance = Math.max( Math.min( this.viewDistance, 32 ), 3 );
this.log( "View Distance: " + this.viewDistance );
this.viewDistance = Math.max(Math.min(this.viewDistance, 32), 3);
this.log("View Distance: " + this.viewDistance);
}
public int simulationDistance;
private void simulationDistance()
{
Object simulationDistanceObject = this.get( "simulation-distance", "default" );
this.simulationDistance = ( simulationDistanceObject ) instanceof Number ? ( (Number) simulationDistanceObject ).intValue() : -1;
if ( this.simulationDistance <= 0 )
{
private void simulationDistance() {
Object simulationDistanceObject = this.get("simulation-distance", "default");
this.simulationDistance = (simulationDistanceObject) instanceof Number ? ((Number) simulationDistanceObject).intValue() : -1;
if (this.simulationDistance <= 0) {
this.simulationDistance = Bukkit.getSimulationDistance();
}
this.log( "Simulation Distance: " + this.simulationDistance );
this.log("Simulation Distance: " + this.simulationDistance);
}
public byte mobSpawnRange;
private void mobSpawnRange()
{
this.mobSpawnRange = (byte) getInt( "mob-spawn-range", 8 ); // Paper - Vanilla
this.log( "Mob Spawn Range: " + this.mobSpawnRange );
private void mobSpawnRange() {
this.mobSpawnRange = (byte) getInt("mob-spawn-range", 8); // Paper - Vanilla
this.log("Mob Spawn Range: " + this.mobSpawnRange);
}
public int itemDespawnRate;
private void itemDespawnRate()
{
this.itemDespawnRate = this.getInt( "item-despawn-rate", 6000 );
this.log( "Item Despawn Rate: " + this.itemDespawnRate );
private void itemDespawnRate() {
this.itemDespawnRate = this.getInt("item-despawn-rate", 6000);
this.log("Item Despawn Rate: " + this.itemDespawnRate);
}
public int animalActivationRange = 32;
@ -216,34 +193,34 @@ public class SpigotWorldConfig
public int waterActivationRange = 16;
public int villagerActivationRange = 32;
public int wakeUpInactiveAnimals = 4;
public int wakeUpInactiveAnimalsEvery = 60*20;
public int wakeUpInactiveAnimalsFor = 5*20;
public int wakeUpInactiveAnimalsEvery = 60 * 20;
public int wakeUpInactiveAnimalsFor = 5 * 20;
public int wakeUpInactiveMonsters = 8;
public int wakeUpInactiveMonstersEvery = 20*20;
public int wakeUpInactiveMonstersFor = 5*20;
public int wakeUpInactiveMonstersEvery = 20 * 20;
public int wakeUpInactiveMonstersFor = 5 * 20;
public int wakeUpInactiveVillagers = 4;
public int wakeUpInactiveVillagersEvery = 30*20;
public int wakeUpInactiveVillagersFor = 5*20;
public int wakeUpInactiveVillagersEvery = 30 * 20;
public int wakeUpInactiveVillagersFor = 5 * 20;
public int wakeUpInactiveFlying = 8;
public int wakeUpInactiveFlyingEvery = 10*20;
public int wakeUpInactiveFlyingFor = 5*20;
public int villagersWorkImmunityAfter = 5*20;
public int wakeUpInactiveFlyingEvery = 10 * 20;
public int wakeUpInactiveFlyingFor = 5 * 20;
public int villagersWorkImmunityAfter = 5 * 20;
public int villagersWorkImmunityFor = 20;
public boolean villagersActiveForPanic = true;
// Paper end
public boolean tickInactiveVillagers = true;
public boolean ignoreSpectatorActivation = false;
private void activationRange()
{
private void activationRange() {
boolean hasAnimalsConfig = config.getInt("entity-activation-range.animals", this.animalActivationRange) != this.animalActivationRange; // Paper
this.animalActivationRange = this.getInt( "entity-activation-range.animals", this.animalActivationRange );
this.monsterActivationRange = this.getInt( "entity-activation-range.monsters", this.monsterActivationRange );
this.raiderActivationRange = this.getInt( "entity-activation-range.raiders", this.raiderActivationRange );
this.miscActivationRange = this.getInt( "entity-activation-range.misc", this.miscActivationRange );
this.animalActivationRange = this.getInt("entity-activation-range.animals", this.animalActivationRange);
this.monsterActivationRange = this.getInt("entity-activation-range.monsters", this.monsterActivationRange);
this.raiderActivationRange = this.getInt("entity-activation-range.raiders", this.raiderActivationRange);
this.miscActivationRange = this.getInt("entity-activation-range.misc", this.miscActivationRange);
// Paper start
this.waterActivationRange = this.getInt( "entity-activation-range.water", this.waterActivationRange );
this.villagerActivationRange = this.getInt( "entity-activation-range.villagers", hasAnimalsConfig ? this.animalActivationRange : this.villagerActivationRange );
this.flyingMonsterActivationRange = this.getInt( "entity-activation-range.flying-monsters", this.flyingMonsterActivationRange );
this.waterActivationRange = this.getInt("entity-activation-range.water", this.waterActivationRange);
this.villagerActivationRange = this.getInt("entity-activation-range.villagers", hasAnimalsConfig ? this.animalActivationRange : this.villagerActivationRange);
this.flyingMonsterActivationRange = this.getInt("entity-activation-range.flying-monsters", this.flyingMonsterActivationRange);
this.wakeUpInactiveAnimals = this.getInt("entity-activation-range.wake-up-inactive.animals-max-per-tick", this.wakeUpInactiveAnimals);
this.wakeUpInactiveAnimalsEvery = this.getInt("entity-activation-range.wake-up-inactive.animals-every", this.wakeUpInactiveAnimalsEvery);
@ -261,13 +238,13 @@ public class SpigotWorldConfig
this.wakeUpInactiveFlyingEvery = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-every", this.wakeUpInactiveFlyingEvery);
this.wakeUpInactiveFlyingFor = this.getInt("entity-activation-range.wake-up-inactive.flying-monsters-for", this.wakeUpInactiveFlyingFor);
this.villagersWorkImmunityAfter = this.getInt( "entity-activation-range.villagers-work-immunity-after", this.villagersWorkImmunityAfter );
this.villagersWorkImmunityFor = this.getInt( "entity-activation-range.villagers-work-immunity-for", this.villagersWorkImmunityFor );
this.villagersActiveForPanic = this.getBoolean( "entity-activation-range.villagers-active-for-panic", this.villagersActiveForPanic );
this.villagersWorkImmunityAfter = this.getInt("entity-activation-range.villagers-work-immunity-after", this.villagersWorkImmunityAfter);
this.villagersWorkImmunityFor = this.getInt("entity-activation-range.villagers-work-immunity-for", this.villagersWorkImmunityFor);
this.villagersActiveForPanic = this.getBoolean("entity-activation-range.villagers-active-for-panic", this.villagersActiveForPanic);
// Paper end
this.tickInactiveVillagers = this.getBoolean( "entity-activation-range.tick-inactive-villagers", this.tickInactiveVillagers );
this.ignoreSpectatorActivation = this.getBoolean( "entity-activation-range.ignore-spectators", this.ignoreSpectatorActivation );
this.log( "Entity Activation Range: An " + this.animalActivationRange + " / Mo " + this.monsterActivationRange + " / Ra " + this.raiderActivationRange + " / Mi " + this.miscActivationRange + " / Tiv " + this.tickInactiveVillagers + " / Isa " + this.ignoreSpectatorActivation );
this.tickInactiveVillagers = this.getBoolean("entity-activation-range.tick-inactive-villagers", this.tickInactiveVillagers);
this.ignoreSpectatorActivation = this.getBoolean("entity-activation-range.ignore-spectators", this.ignoreSpectatorActivation);
this.log("Entity Activation Range: An " + this.animalActivationRange + " / Mo " + this.monsterActivationRange + " / Ra " + this.raiderActivationRange + " / Mi " + this.miscActivationRange + " / Tiv " + this.tickInactiveVillagers + " / Isa " + this.ignoreSpectatorActivation);
}
public int playerTrackingRange = 128;
@ -276,81 +253,71 @@ public class SpigotWorldConfig
public int miscTrackingRange = 96;
public int displayTrackingRange = 128;
public int otherTrackingRange = 64;
private void trackingRange()
{
this.playerTrackingRange = this.getInt( "entity-tracking-range.players", this.playerTrackingRange );
this.animalTrackingRange = this.getInt( "entity-tracking-range.animals", this.animalTrackingRange );
this.monsterTrackingRange = this.getInt( "entity-tracking-range.monsters", this.monsterTrackingRange );
this.miscTrackingRange = this.getInt( "entity-tracking-range.misc", this.miscTrackingRange );
this.displayTrackingRange = this.getInt( "entity-tracking-range.display", this.displayTrackingRange );
this.otherTrackingRange = this.getInt( "entity-tracking-range.other", this.otherTrackingRange );
this.log( "Entity Tracking Range: Pl " + this.playerTrackingRange + " / An " + this.animalTrackingRange + " / Mo " + this.monsterTrackingRange + " / Mi " + this.miscTrackingRange + " / Di " + this.displayTrackingRange + " / Other " + this.otherTrackingRange );
private void trackingRange() {
this.playerTrackingRange = this.getInt("entity-tracking-range.players", this.playerTrackingRange);
this.animalTrackingRange = this.getInt("entity-tracking-range.animals", this.animalTrackingRange);
this.monsterTrackingRange = this.getInt("entity-tracking-range.monsters", this.monsterTrackingRange);
this.miscTrackingRange = this.getInt("entity-tracking-range.misc", this.miscTrackingRange);
this.displayTrackingRange = this.getInt("entity-tracking-range.display", this.displayTrackingRange);
this.otherTrackingRange = this.getInt("entity-tracking-range.other", this.otherTrackingRange);
this.log("Entity Tracking Range: Pl " + this.playerTrackingRange + " / An " + this.animalTrackingRange + " / Mo " + this.monsterTrackingRange + " / Mi " + this.miscTrackingRange + " / Di " + this.displayTrackingRange + " / Other " + this.otherTrackingRange);
}
public int hopperTransfer;
public int hopperCheck;
public int hopperAmount;
public boolean hopperCanLoadChunks;
private void hoppers()
{
private void hoppers() {
// Set the tick delay between hopper item movements
this.hopperTransfer = this.getInt( "ticks-per.hopper-transfer", 8 );
if ( SpigotConfig.version < 11 )
{
this.set( "ticks-per.hopper-check", 1 );
this.hopperTransfer = this.getInt("ticks-per.hopper-transfer", 8);
if (SpigotConfig.version < 11) {
this.set("ticks-per.hopper-check", 1);
}
this.hopperCheck = this.getInt( "ticks-per.hopper-check", 1 );
this.hopperAmount = this.getInt( "hopper-amount", 1 );
this.hopperCanLoadChunks = this.getBoolean( "hopper-can-load-chunks", false );
this.log( "Hopper Transfer: " + this.hopperTransfer + " Hopper Check: " + this.hopperCheck + " Hopper Amount: " + this.hopperAmount + " Hopper Can Load Chunks: " + this.hopperCanLoadChunks );
this.hopperCheck = this.getInt("ticks-per.hopper-check", 1);
this.hopperAmount = this.getInt("hopper-amount", 1);
this.hopperCanLoadChunks = this.getBoolean("hopper-can-load-chunks", false);
this.log("Hopper Transfer: " + this.hopperTransfer + " Hopper Check: " + this.hopperCheck + " Hopper Amount: " + this.hopperAmount + " Hopper Can Load Chunks: " + this.hopperCanLoadChunks);
}
public int arrowDespawnRate;
public int tridentDespawnRate;
private void arrowDespawnRate()
{
this.arrowDespawnRate = this.getInt( "arrow-despawn-rate", 1200 );
this.tridentDespawnRate = this.getInt( "trident-despawn-rate", this.arrowDespawnRate );
this.log( "Arrow Despawn Rate: " + this.arrowDespawnRate + " Trident Respawn Rate:" + this.tridentDespawnRate );
private void arrowDespawnRate() {
this.arrowDespawnRate = this.getInt("arrow-despawn-rate", 1200);
this.tridentDespawnRate = this.getInt("trident-despawn-rate", this.arrowDespawnRate);
this.log("Arrow Despawn Rate: " + this.arrowDespawnRate + " Trident Respawn Rate:" + this.tridentDespawnRate);
}
public boolean zombieAggressiveTowardsVillager;
private void zombieAggressiveTowardsVillager()
{
this.zombieAggressiveTowardsVillager = this.getBoolean( "zombie-aggressive-towards-villager", true );
this.log( "Zombie Aggressive Towards Villager: " + this.zombieAggressiveTowardsVillager );
private void zombieAggressiveTowardsVillager() {
this.zombieAggressiveTowardsVillager = this.getBoolean("zombie-aggressive-towards-villager", true);
this.log("Zombie Aggressive Towards Villager: " + this.zombieAggressiveTowardsVillager);
}
public boolean nerfSpawnerMobs;
private void nerfSpawnerMobs()
{
this.nerfSpawnerMobs = this.getBoolean( "nerf-spawner-mobs", false );
this.log( "Nerfing mobs spawned from spawners: " + this.nerfSpawnerMobs );
private void nerfSpawnerMobs() {
this.nerfSpawnerMobs = this.getBoolean("nerf-spawner-mobs", false);
this.log("Nerfing mobs spawned from spawners: " + this.nerfSpawnerMobs);
}
public boolean enableZombiePigmenPortalSpawns;
private void enableZombiePigmenPortalSpawns()
{
this.enableZombiePigmenPortalSpawns = this.getBoolean( "enable-zombie-pigmen-portal-spawns", true );
this.log( "Allow Zombie Pigmen to spawn from portal blocks: " + this.enableZombiePigmenPortalSpawns );
private void enableZombiePigmenPortalSpawns() {
this.enableZombiePigmenPortalSpawns = this.getBoolean("enable-zombie-pigmen-portal-spawns", true);
this.log("Allow Zombie Pigmen to spawn from portal blocks: " + this.enableZombiePigmenPortalSpawns);
}
public int dragonDeathSoundRadius;
private void keepDragonDeathPerWorld()
{
this.dragonDeathSoundRadius = this.getInt( "dragon-death-sound-radius", 0 );
private void keepDragonDeathPerWorld() {
this.dragonDeathSoundRadius = this.getInt("dragon-death-sound-radius", 0);
}
public int witherSpawnSoundRadius;
private void witherSpawnSoundRadius()
{
this.witherSpawnSoundRadius = this.getInt( "wither-spawn-sound-radius", 0 );
private void witherSpawnSoundRadius() {
this.witherSpawnSoundRadius = this.getInt("wither-spawn-sound-radius", 0);
}
public int endPortalSoundRadius;
private void endPortalSoundRadius()
{
this.endPortalSoundRadius = this.getInt( "end-portal-sound-radius", 0 );
private void endPortalSoundRadius() {
this.endPortalSoundRadius = this.getInt("end-portal-sound-radius", 0);
}
public int villageSeed;
@ -375,28 +342,29 @@ public class SpigotWorldConfig
public int buriedTreasureSeed;
public Integer mineshaftSeed;
public Long strongholdSeed;
private <N extends Number> N getSeed(String path, java.util.function.Function<String, N> toNumberFunc) {
final String value = this.getString(path, "default");
return org.apache.commons.lang3.math.NumberUtils.isParsable(value) ? toNumberFunc.apply(value) : null;
}
// Paper end
private void initWorldGenSeeds()
{
this.villageSeed = this.getInt( "seed-village", 10387312 );
this.desertSeed = this.getInt( "seed-desert", 14357617 );
this.iglooSeed = this.getInt( "seed-igloo", 14357618 );
this.jungleSeed = this.getInt( "seed-jungle", 14357619 );
this.swampSeed = this.getInt( "seed-swamp", 14357620 );
this.monumentSeed = this.getInt( "seed-monument", 10387313 );
this.shipwreckSeed = this.getInt( "seed-shipwreck", 165745295 );
this.oceanSeed = this.getInt( "seed-ocean", 14357621 );
this.outpostSeed = this.getInt( "seed-outpost", 165745296 );
this.endCitySeed = this.getInt( "seed-endcity", 10387313 );
this.slimeSeed = this.getInt( "seed-slime", 987234911 );
this.netherSeed = this.getInt( "seed-nether", 30084232 );
this.mansionSeed = this.getInt( "seed-mansion", 10387319 );
this.fossilSeed = this.getInt( "seed-fossil", 14357921 );
this.portalSeed = this.getInt( "seed-portal", 34222645 );
private void initWorldGenSeeds() {
this.villageSeed = this.getInt("seed-village", 10387312);
this.desertSeed = this.getInt("seed-desert", 14357617);
this.iglooSeed = this.getInt("seed-igloo", 14357618);
this.jungleSeed = this.getInt("seed-jungle", 14357619);
this.swampSeed = this.getInt("seed-swamp", 14357620);
this.monumentSeed = this.getInt("seed-monument", 10387313);
this.shipwreckSeed = this.getInt("seed-shipwreck", 165745295);
this.oceanSeed = this.getInt("seed-ocean", 14357621);
this.outpostSeed = this.getInt("seed-outpost", 165745296);
this.endCitySeed = this.getInt("seed-endcity", 10387313);
this.slimeSeed = this.getInt("seed-slime", 987234911);
this.netherSeed = this.getInt("seed-nether", 30084232);
this.mansionSeed = this.getInt("seed-mansion", 10387319);
this.fossilSeed = this.getInt("seed-fossil", 14357921);
this.portalSeed = this.getInt("seed-portal", 34222645);
// Paper start - add missing structure set configs
this.ancientCitySeed = this.getInt("seed-ancientcity", 20083232);
this.trailRuinsSeed = this.getInt("seed-trailruins", 83469867);
@ -405,8 +373,8 @@ public class SpigotWorldConfig
this.mineshaftSeed = this.getSeed("seed-mineshaft", Integer::parseInt);
this.strongholdSeed = this.getSeed("seed-stronghold", Long::parseLong);
// Paper end
this.log( "Custom Map Seeds: Village: " + this.villageSeed + " Desert: " + this.desertSeed + " Igloo: " + this.iglooSeed + " Jungle: " + this.jungleSeed + " Swamp: " + this.swampSeed + " Monument: " + this.monumentSeed
+ " Ocean: " + this.oceanSeed + " Shipwreck: " + this.shipwreckSeed + " End City: " + this.endCitySeed + " Slime: " + this.slimeSeed + " Nether: " + this.netherSeed + " Mansion: " + this.mansionSeed + " Fossil: " + this.fossilSeed + " Portal: " + this.portalSeed );
this.log("Custom Map Seeds: Village: " + this.villageSeed + " Desert: " + this.desertSeed + " Igloo: " + this.iglooSeed + " Jungle: " + this.jungleSeed + " Swamp: " + this.swampSeed + " Monument: " + this.monumentSeed
+ " Ocean: " + this.oceanSeed + " Shipwreck: " + this.shipwreckSeed + " End City: " + this.endCitySeed + " Slime: " + this.slimeSeed + " Nether: " + this.netherSeed + " Mansion: " + this.mansionSeed + " Fossil: " + this.fossilSeed + " Portal: " + this.portalSeed);
}
public float jumpWalkExhaustion;
@ -416,54 +384,48 @@ public class SpigotWorldConfig
public float swimMultiplier;
public float sprintMultiplier;
public float otherMultiplier;
private void initHunger()
{
if ( SpigotConfig.version < 10 )
{
this.set( "hunger.walk-exhaustion", null );
this.set( "hunger.sprint-exhaustion", null );
this.set( "hunger.combat-exhaustion", 0.1 );
this.set( "hunger.regen-exhaustion", 6.0 );
private void initHunger() {
if (SpigotConfig.version < 10) {
this.set("hunger.walk-exhaustion", null);
this.set("hunger.sprint-exhaustion", null);
this.set("hunger.combat-exhaustion", 0.1);
this.set("hunger.regen-exhaustion", 6.0);
}
this.jumpWalkExhaustion = (float) this.getDouble( "hunger.jump-walk-exhaustion", 0.05 );
this.jumpSprintExhaustion = (float) this.getDouble( "hunger.jump-sprint-exhaustion", 0.2 );
this.combatExhaustion = (float) this.getDouble( "hunger.combat-exhaustion", 0.1 );
this.regenExhaustion = (float) this.getDouble( "hunger.regen-exhaustion", 6.0 );
this.swimMultiplier = (float) this.getDouble( "hunger.swim-multiplier", 0.01 );
this.sprintMultiplier = (float) this.getDouble( "hunger.sprint-multiplier", 0.1 );
this.otherMultiplier = (float) this.getDouble( "hunger.other-multiplier", 0.0 );
this.jumpWalkExhaustion = (float) this.getDouble("hunger.jump-walk-exhaustion", 0.05);
this.jumpSprintExhaustion = (float) this.getDouble("hunger.jump-sprint-exhaustion", 0.2);
this.combatExhaustion = (float) this.getDouble("hunger.combat-exhaustion", 0.1);
this.regenExhaustion = (float) this.getDouble("hunger.regen-exhaustion", 6.0);
this.swimMultiplier = (float) this.getDouble("hunger.swim-multiplier", 0.01);
this.sprintMultiplier = (float) this.getDouble("hunger.sprint-multiplier", 0.1);
this.otherMultiplier = (float) this.getDouble("hunger.other-multiplier", 0.0);
}
public int currentPrimedTnt = 0;
public int maxTntTicksPerTick;
private void maxTntPerTick() {
if ( SpigotConfig.version < 7 )
{
this.set( "max-tnt-per-tick", 100 );
if (SpigotConfig.version < 7) {
this.set("max-tnt-per-tick", 100);
}
this.maxTntTicksPerTick = this.getInt( "max-tnt-per-tick", 100 );
this.log( "Max TNT Explosions: " + this.maxTntTicksPerTick );
this.maxTntTicksPerTick = this.getInt("max-tnt-per-tick", 100);
this.log("Max TNT Explosions: " + this.maxTntTicksPerTick);
}
public int hangingTickFrequency;
private void hangingTickFrequency()
{
this.hangingTickFrequency = this.getInt( "hanging-tick-frequency", 100 );
private void hangingTickFrequency() {
this.hangingTickFrequency = this.getInt("hanging-tick-frequency", 100);
}
public int tileMaxTickTime;
public int entityMaxTickTime;
private void maxTickTimes()
{
private void maxTickTimes() {
this.tileMaxTickTime = this.getInt("max-tick-time.tile", 50);
this.entityMaxTickTime = this.getInt("max-tick-time.entity", 50);
this.log("Tile Max Tick Time: " + this.tileMaxTickTime + "ms Entity max Tick Time: " + this.entityMaxTickTime + "ms");
}
public int thunderChance;
private void thunderChance()
{
private void thunderChance() {
this.thunderChance = this.getInt("thunder-chance", 100000);
}

Datei anzeigen

@ -5,8 +5,8 @@ public class TickLimiter {
private final int maxTime;
private long startTime;
public TickLimiter(int maxtime) {
this.maxTime = maxtime;
public TickLimiter(int maxTime) {
this.maxTime = maxTime;
}
public void initTick() {

Datei anzeigen

@ -1,51 +1,55 @@
package org.spigotmc;
import net.minecraft.server.MinecraftServer;
import org.bukkit.ChatColor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
public class TicksPerSecondCommand extends Command
{
import static net.kyori.adventure.text.Component.text;
public TicksPerSecondCommand(String name)
{
super( name );
public class TicksPerSecondCommand extends Command {
private boolean hasShownMemoryWarning; // Paper
public TicksPerSecondCommand(String name) {
super(name);
this.description = "Gets the current ticks per second for the server";
this.usageMessage = "/tps";
this.setPermission( "bukkit.command.tps" );
this.setPermission("bukkit.command.tps");
}
// Paper start
private static final net.kyori.adventure.text.Component WARN_MSG = net.kyori.adventure.text.Component.text()
.append(net.kyori.adventure.text.Component.text("Warning: ", net.kyori.adventure.text.format.NamedTextColor.RED))
.append(net.kyori.adventure.text.Component.text("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.", net.kyori.adventure.text.format.NamedTextColor.GOLD))
private static final Component WARN_MSG = text()
.append(text("Warning: ", NamedTextColor.RED))
.append(text("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.", NamedTextColor.GOLD))
.build();
// Paper end
@Override
public boolean execute(CommandSender sender, String currentAlias, String[] args)
{
if ( !this.testPermission( sender ) )
{
public boolean execute(CommandSender sender, String currentAlias, String[] args) {
if (!this.testPermission(sender)) {
return true;
}
// Paper start - Further improve tick handling
double[] tps = org.bukkit.Bukkit.getTPS();
net.kyori.adventure.text.Component[] tpsAvg = new net.kyori.adventure.text.Component[tps.length];
Component[] tpsAvg = new Component[tps.length];
for ( int i = 0; i < tps.length; i++) {
tpsAvg[i] = TicksPerSecondCommand.format( tps[i] );
for (int i = 0; i < tps.length; i++) {
tpsAvg[i] = TicksPerSecondCommand.format(tps[i]);
}
net.kyori.adventure.text.TextComponent.Builder builder = net.kyori.adventure.text.Component.text();
builder.append(net.kyori.adventure.text.Component.text("TPS from last 1m, 5m, 15m: ", net.kyori.adventure.text.format.NamedTextColor.GOLD));
builder.append(net.kyori.adventure.text.Component.join(net.kyori.adventure.text.JoinConfiguration.commas(true), tpsAvg));
TextComponent.Builder builder = text();
builder.append(text("TPS from last 1m, 5m, 15m: ", NamedTextColor.GOLD));
builder.append(Component.join(JoinConfiguration.commas(true), tpsAvg));
sender.sendMessage(builder.asComponent());
if (args.length > 0 && args[0].equals("mem") && sender.hasPermission("bukkit.command.tpsmemory")) {
sender.sendMessage(net.kyori.adventure.text.Component.text()
.append(net.kyori.adventure.text.Component.text("Current Memory Usage: ", net.kyori.adventure.text.format.NamedTextColor.GOLD))
.append(net.kyori.adventure.text.Component.text(((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)", net.kyori.adventure.text.format.NamedTextColor.GREEN))
sender.sendMessage(text()
.append(text("Current Memory Usage: ", NamedTextColor.GOLD))
.append(text(((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)) + "/" + (Runtime.getRuntime().totalMemory() / (1024 * 1024)) + " mb (Max: " + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + " mb)", NamedTextColor.GREEN))
);
if (!this.hasShownMemoryWarning) {
sender.sendMessage(WARN_MSG);
@ -57,13 +61,11 @@ public class TicksPerSecondCommand extends Command
return true;
}
private boolean hasShownMemoryWarning; // Paper
private static net.kyori.adventure.text.Component format(double tps) // Paper - Made static
{
// Paper
net.kyori.adventure.text.format.TextColor color = ( ( tps > 18.0 ) ? net.kyori.adventure.text.format.NamedTextColor.GREEN : ( tps > 16.0 ) ? net.kyori.adventure.text.format.NamedTextColor.YELLOW : net.kyori.adventure.text.format.NamedTextColor.RED );
String amount = Math.min(Math.round(tps * 100.0) / 100.0, 20.0) + (tps > 21.0 ? "*" : ""); // Paper - only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise
return net.kyori.adventure.text.Component.text(amount, color);
private static Component format(double tps) { // Paper - Made static
// Paper start
TextColor color = ((tps > 18.0) ? NamedTextColor.GREEN : (tps > 16.0) ? NamedTextColor.YELLOW : NamedTextColor.RED);
String amount = Math.min(Math.round(tps * 100.0) / 100.0, 20.0) + (tps > 21.0 ? "*" : ""); // Paper - only print * at 21, we commonly peak to 20.02 as the tick sleep is not accurate enough, stop the noise
return text(amount, color);
// Paper end
}
}

Datei anzeigen

@ -18,9 +18,7 @@ public final class TrackingRange {
* Gets the range an entity should be 'tracked' by players and visible in
* the client.
*
* @param entity
* @param defaultRange Default range defined by Mojang
* @return
*/
public static int getEntityTrackingRange(final Entity entity, final int defaultRange) {
if (defaultRange == 0) {
@ -51,7 +49,7 @@ public final class TrackingRange {
} else {
if (entity instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon) {
// Exempt ender dragon
return ((ServerLevel) entity.getCommandSenderWorld()).getChunkSource().chunkMap.serverViewDistance;
return ((ServerLevel) entity.level()).getChunkSource().chunkMap.serverViewDistance;
}
return config.otherTrackingRange;
}

Datei anzeigen

@ -5,11 +5,12 @@ import java.lang.management.MonitorInfo;
import java.lang.management.ThreadInfo;
import java.util.logging.Level;
import java.util.logging.Logger;
import io.papermc.paper.configuration.GlobalConfiguration;
import net.minecraft.server.MinecraftServer;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftServer;
public class WatchdogThread extends Thread
{
public class WatchdogThread extends Thread {
private static WatchdogThread instance;
private long timeoutTime;
@ -21,160 +22,141 @@ public class WatchdogThread extends Thread
private volatile long lastTick;
private volatile boolean stopping;
private WatchdogThread(long timeoutTime, boolean restart)
{
super( "Paper Watchdog Thread" );
private WatchdogThread(long timeoutTime, boolean restart) {
super("Paper Watchdog Thread");
this.timeoutTime = timeoutTime;
this.restart = restart;
earlyWarningEvery = Math.min(io.papermc.paper.configuration.GlobalConfiguration.get().watchdog.earlyWarningEvery, timeoutTime); // Paper
earlyWarningDelay = Math.min(io.papermc.paper.configuration.GlobalConfiguration.get().watchdog.earlyWarningDelay, timeoutTime); // Paper
this.earlyWarningEvery = Math.min(GlobalConfiguration.get().watchdog.earlyWarningEvery, timeoutTime); // Paper
this.earlyWarningDelay = Math.min(GlobalConfiguration.get().watchdog.earlyWarningDelay, timeoutTime); // Paper
}
private static long monotonicMillis()
{
private static long monotonicMillis() {
return System.nanoTime() / 1000000L;
}
public static void doStart(int timeoutTime, boolean restart)
{
if ( WatchdogThread.instance == null )
{
WatchdogThread.instance = new WatchdogThread( timeoutTime * 1000L, restart );
public static void doStart(int timeoutTime, boolean restart) {
if (WatchdogThread.instance == null) {
WatchdogThread.instance = new WatchdogThread(timeoutTime * 1000L, restart);
WatchdogThread.instance.start();
} else
{
} else {
WatchdogThread.instance.timeoutTime = timeoutTime * 1000L;
WatchdogThread.instance.restart = restart;
}
}
public static void tick()
{
public static void tick() {
WatchdogThread.instance.lastTick = WatchdogThread.monotonicMillis();
}
public static void doStop()
{
if ( WatchdogThread.instance != null )
{
public static void doStop() {
if (WatchdogThread.instance != null) {
WatchdogThread.instance.stopping = true;
}
}
@Override
public void run()
{
while ( !this.stopping )
{
//
public void run() {
while (!this.stopping) {
// Paper start
Logger log = Bukkit.getServer().getLogger();
Logger logger = Bukkit.getServer().getLogger();
long currentTime = WatchdogThread.monotonicMillis();
if ( this.lastTick != 0 && this.timeoutTime > 0 && currentTime > this.lastTick + this.earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
{
boolean isLongTimeout = currentTime > lastTick + timeoutTime;
if (this.lastTick != 0 && this.timeoutTime > 0 && currentTime > this.lastTick + this.earlyWarningEvery && !Boolean.getBoolean("disable.watchdog")) { // Paper - Add property to disable
boolean isLongTimeout = currentTime > this.lastTick + this.timeoutTime;
// Don't spam early warning dumps
if ( !isLongTimeout && (earlyWarningEvery <= 0 || !hasStarted || currentTime < lastEarlyWarning + earlyWarningEvery || currentTime < lastTick + earlyWarningDelay)) continue;
if ( !isLongTimeout && MinecraftServer.getServer().hasStopped()) continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
lastEarlyWarning = currentTime;
if (!isLongTimeout && (this.earlyWarningEvery <= 0 ||
!hasStarted || currentTime < this.lastEarlyWarning + this.earlyWarningEvery ||
currentTime < this.lastTick + this.earlyWarningDelay))
continue;
if (!isLongTimeout && MinecraftServer.getServer().hasStopped())
continue; // Don't spam early watchdog warnings during shutdown, we'll come back to this...
this.lastEarlyWarning = currentTime;
if (isLongTimeout) {
// Paper end
log.log( Level.SEVERE, "------------------------------" );
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 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, "Paper version: " + Bukkit.getServer().getVersion() );
//
if ( net.minecraft.world.level.Level.lastPhysicsProblem != null )
{
log.log( Level.SEVERE, "------------------------------" );
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
logger.log(Level.SEVERE, "------------------------------");
logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug."); // Paper
logger.log(Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author");
logger.log(Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring");
logger.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");
logger.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");
logger.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");
logger.log(Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports");
logger.log(Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion());
if (net.minecraft.world.level.Level.lastPhysicsProblem != null) {
logger.log(Level.SEVERE, "------------------------------");
logger.log(Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed");
logger.log(Level.SEVERE, "near " + net.minecraft.world.level.Level.lastPhysicsProblem);
}
}
// Paper end
} else
{
log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH - " + Bukkit.getServer().getVersion() + " ---");
log.log(Level.SEVERE, "The server has not responded for " + (currentTime - lastTick) / 1000 + " seconds! Creating thread dump");
// Paper start - Warn in watchdog if an excessive velocity was ever set
if (CraftServer.excessiveVelEx != null) {
logger.log(Level.SEVERE, "------------------------------");
logger.log(Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity");
logger.log(Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated");
logger.log(Level.SEVERE, CraftServer.excessiveVelEx.getMessage());
for (StackTraceElement stack : CraftServer.excessiveVelEx.getStackTrace()) {
logger.log(Level.SEVERE, "\t\t" + stack);
}
}
// Paper end
} else {
logger.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH - " + Bukkit.getServer().getVersion() + " ---");
logger.log(Level.SEVERE, "The server has not responded for " + (currentTime - lastTick) / 1000 + " seconds! Creating thread dump");
}
// Paper end - Different message for short timeout
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 );
log.log( Level.SEVERE, "------------------------------" );
//
logger.log(Level.SEVERE, "------------------------------");
logger.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), logger);
logger.log(Level.SEVERE, "------------------------------");
// Paper start - Only print full dump on long timeouts
if ( isLongTimeout )
{
log.log( Level.SEVERE, "Entire Thread Dump:" );
ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads( true, true );
for ( ThreadInfo thread : threads )
{
WatchdogThread.dumpThread( thread, log );
}
if (isLongTimeout) {
logger.log(Level.SEVERE, "Entire Thread Dump:");
ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(true, true);
for (ThreadInfo thread : threads) {
WatchdogThread.dumpThread(thread, logger);
}
} else {
log.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH ---");
logger.log(Level.SEVERE, "--- DO NOT REPORT THIS TO PAPER - THIS IS NOT A BUG OR A CRASH ---");
}
log.log( Level.SEVERE, "------------------------------" );
logger.log(Level.SEVERE, "------------------------------");
if ( isLongTimeout )
{
if ( this.restart && !MinecraftServer.getServer().hasStopped() )
{
RestartCommand.restart();
if (isLongTimeout) {
if (this.restart && !MinecraftServer.getServer().hasStopped()) {
RestartCommand.restart();
}
break;
}
break;
} // Paper end
// Paper end
}
try
{
sleep( 1000 ); // Paper - Reduce check time to every second instead of every ten seconds, more consistent and allows for short timeout
} catch ( InterruptedException ex )
{
try {
sleep(1000); // Paper - Reduce check time to every second instead of every ten seconds, more consistent and allows for short timeout
} catch (InterruptedException ex) {
this.interrupt();
}
}
}
private static void dumpThread(ThreadInfo thread, Logger log)
{
log.log( Level.SEVERE, "------------------------------" );
//
log.log( Level.SEVERE, "Current Thread: " + thread.getThreadName() );
log.log( Level.SEVERE, "\tPID: " + thread.getThreadId()
+ " | Suspended: " + thread.isSuspended()
+ " | Native: " + thread.isInNative()
+ " | State: " + thread.getThreadState() );
if ( thread.getLockedMonitors().length != 0 )
{
log.log( Level.SEVERE, "\tThread is waiting on monitor(s):" );
for ( MonitorInfo monitor : thread.getLockedMonitors() )
{
log.log( Level.SEVERE, "\t\tLocked on:" + monitor.getLockedStackFrame() );
private static void dumpThread(ThreadInfo thread, Logger log) {
log.log(Level.SEVERE, "------------------------------");
log.log(Level.SEVERE, "Current Thread: " + thread.getThreadName());
log.log(Level.SEVERE, "\tPID: " + thread.getThreadId()
+ " | Suspended: " + thread.isSuspended()
+ " | Native: " + thread.isInNative()
+ " | State: " + thread.getThreadState());
if (thread.getLockedMonitors().length != 0) {
log.log(Level.SEVERE, "\tThread is waiting on monitor(s):");
for (MonitorInfo monitor : thread.getLockedMonitors()) {
log.log(Level.SEVERE, "\t\tLocked on:" + monitor.getLockedStackFrame());
}
}
log.log( Level.SEVERE, "\tStack:" );
//
for ( StackTraceElement stack : io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace()) ) // Paper
{
log.log( Level.SEVERE, "\t\t" + stack );
log.log(Level.SEVERE, "\tStack:");
for (StackTraceElement stack : io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateStacktrace(thread.getStackTrace())) { // Paper
log.log(Level.SEVERE, "\t\t" + stack);
}
}
}