reformat spigot package

This commit is contained in:
Lulu13022002 2024-12-16 19:22:36 +01:00
parent 7d29c678f7
commit 57c683647f
No known key found for this signature in database
GPG key ID: 491C8F0B8ACDEB01
11 changed files with 559 additions and 1376 deletions

View file

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

View file

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

View file

@ -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();
}
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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