SportPaper patches
This commit is contained in:
parent
cb9fadbb9f
commit
e48bcb5e7a
@ -29,6 +29,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.Recipe;
|
||||
import org.bukkit.map.MapView;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.ServicesManager;
|
||||
import org.bukkit.plugin.messaging.Messenger;
|
||||
@ -1162,6 +1163,14 @@ public final class Bukkit {
|
||||
}
|
||||
// Paper end
|
||||
|
||||
public static void postToMainThread(Plugin plugin, boolean priority, Runnable task) {
|
||||
server.postToMainThread(plugin, priority, task);
|
||||
}
|
||||
|
||||
public static boolean runOnMainThread(Plugin plugin, boolean priority, Runnable task) {
|
||||
return server.runOnMainThread(plugin, priority, task);
|
||||
}
|
||||
|
||||
public static Server.Spigot spigot()
|
||||
{
|
||||
return server.spigot();
|
||||
|
@ -4,6 +4,8 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a chunk of blocks
|
||||
*/
|
||||
@ -40,6 +42,14 @@ public interface Chunk {
|
||||
*/
|
||||
Block getBlock(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Get all blocks in this chunk that are made of the given {@link Material}
|
||||
*
|
||||
* @param material type of block to search for
|
||||
* @return all blocks found
|
||||
*/
|
||||
Set<Block> getBlocks(Material material);
|
||||
|
||||
/**
|
||||
* Capture thread-safe read-only snapshot of chunk data
|
||||
*
|
||||
|
@ -29,6 +29,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.Recipe;
|
||||
import org.bukkit.map.MapView;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.ServicesManager;
|
||||
import org.bukkit.plugin.messaging.Messenger;
|
||||
@ -950,6 +951,28 @@ public interface Server extends PluginMessageRecipient {
|
||||
CommandMap getCommandMap();
|
||||
// Paper end
|
||||
|
||||
/**
|
||||
* Post the given task to the main thread queue. This is the queue used to handle
|
||||
* incoming packets (NOT the {@link BukkitScheduler} queue).
|
||||
*
|
||||
* The priority flag determines which end of the queue the task is posted to, and
|
||||
* therefor whether it will run before (true) or after (false) any other tasks
|
||||
* that are currently queued.
|
||||
*
|
||||
* Since incoming packets are also handled through this queue,
|
||||
*/
|
||||
void postToMainThread(Plugin plugin, boolean priority, Runnable task);
|
||||
|
||||
/**
|
||||
* If called on the main thread, run the given task immediately and return when
|
||||
* the task completes. If run from any other thread, this is the same as calling
|
||||
* {@link #postToMainThread(Plugin, boolean, Runnable)}.
|
||||
*
|
||||
* @return true if the task ran synchronously,
|
||||
* false if it was added to the main thread queue
|
||||
*/
|
||||
boolean runOnMainThread(Plugin plugin, boolean priority, Runnable task);
|
||||
|
||||
class Spigot
|
||||
{
|
||||
@Deprecated
|
||||
|
@ -32,7 +32,7 @@ public class VersionCommand extends BukkitCommand {
|
||||
|
||||
if (args.length == 0) {
|
||||
String[] message = new String[] {
|
||||
"§3This server is running §b§leSpigot§3 by the ElevateMC development team. Version §b§l1.8.8",
|
||||
"§3This server is running §b§leSpigot§3 by the ElevateMC development team. Version §b§l1.8.9",
|
||||
};
|
||||
|
||||
sender.sendMessage(message);
|
||||
|
@ -119,6 +119,26 @@ public abstract class MetadataStoreBase<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all metadata in the metadata store that originates from the
|
||||
* given plugin.
|
||||
*
|
||||
* @param owningPlugin the plugin requesting the invalidation.
|
||||
* @throws IllegalArgumentException If plugin is null
|
||||
*/
|
||||
public void removeAll(Plugin owningPlugin) {
|
||||
Validate.notNull(owningPlugin, "Plugin cannot be null");
|
||||
for (Iterator<Map<Plugin, MetadataValue>> iterator = metadataMap.values().iterator(); iterator.hasNext(); ) {
|
||||
Map<Plugin, MetadataValue> values = iterator.next();
|
||||
if (values.containsKey(owningPlugin)) {
|
||||
values.remove(owningPlugin);
|
||||
}
|
||||
if (values.isEmpty()) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a unique name for the object receiving metadata by combining
|
||||
* unique data from the subject with a metadataKey.
|
||||
|
@ -0,0 +1,36 @@
|
||||
package org.github.paperspigot.event;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.github.paperspigot.exception.ServerException;
|
||||
|
||||
/**
|
||||
* Called whenever an exception is thrown in a recoverable section of the server.
|
||||
*/
|
||||
public class ServerExceptionEvent extends Event {
|
||||
private static final HandlerList handlers = new HandlerList();
|
||||
private ServerException exception;
|
||||
|
||||
public ServerExceptionEvent (ServerException exception) {
|
||||
this.exception = Preconditions.checkNotNull(exception, "exception");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wrapped exception that was thrown.
|
||||
* @return Exception thrown
|
||||
*/
|
||||
public ServerException getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return handlers;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return handlers;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package org.github.paperspigot.exception;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Thrown when a command throws an exception
|
||||
*/
|
||||
public class ServerCommandException extends ServerException {
|
||||
|
||||
private final Command command;
|
||||
private final CommandSender commandSender;
|
||||
private final String[] arguments;
|
||||
|
||||
public ServerCommandException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
|
||||
super(message, cause);
|
||||
this.commandSender = checkNotNull(commandSender, "commandSender");
|
||||
this.arguments = checkNotNull(arguments, "arguments");
|
||||
this.command = checkNotNull(command, "command");
|
||||
}
|
||||
|
||||
public ServerCommandException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
|
||||
super(cause);
|
||||
this.commandSender = checkNotNull(commandSender, "commandSender");
|
||||
this.arguments = checkNotNull(arguments, "arguments");
|
||||
this.command = checkNotNull(command, "command");
|
||||
}
|
||||
|
||||
protected ServerCommandException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
this.commandSender = checkNotNull(commandSender, "commandSender");
|
||||
this.arguments = checkNotNull(arguments, "arguments");
|
||||
this.command = checkNotNull(command, "command");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command which threw the exception
|
||||
*
|
||||
* @return exception throwing command
|
||||
*/
|
||||
public Command getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command sender which executed the command request
|
||||
*
|
||||
* @return command sender of exception thrown command request
|
||||
*/
|
||||
public CommandSender getCommandSender() {
|
||||
return commandSender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the arguments which threw the exception for the command
|
||||
*
|
||||
* @return arguments of exception thrown command request
|
||||
*/
|
||||
public String[] getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package org.github.paperspigot.exception;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Exception thrown when a server event listener throws an exception
|
||||
*/
|
||||
public class ServerEventException extends ServerPluginException {
|
||||
|
||||
private final Listener listener;
|
||||
private final Event event;
|
||||
|
||||
public ServerEventException(String message, Throwable cause, Plugin responsiblePlugin, Listener listener, Event event) {
|
||||
super(message, cause, responsiblePlugin);
|
||||
this.listener = checkNotNull(listener, "listener");
|
||||
this.event = checkNotNull(event, "event");
|
||||
}
|
||||
|
||||
public ServerEventException(Throwable cause, Plugin responsiblePlugin, Listener listener, Event event) {
|
||||
super(cause, responsiblePlugin);
|
||||
this.listener = checkNotNull(listener, "listener");
|
||||
this.event = checkNotNull(event, "event");
|
||||
}
|
||||
|
||||
protected ServerEventException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin, Listener listener, Event event) {
|
||||
super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin);
|
||||
this.listener = checkNotNull(listener, "listener");
|
||||
this.event = checkNotNull(event, "event");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the listener which threw the exception
|
||||
*
|
||||
* @return event listener
|
||||
*/
|
||||
public Listener getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the event which caused the exception
|
||||
*
|
||||
* @return event
|
||||
*/
|
||||
public Event getEvent() {
|
||||
return event;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.github.paperspigot.exception;
|
||||
|
||||
/**
|
||||
* Wrapper exception for all exceptions that are thrown by the server.
|
||||
*/
|
||||
public class ServerException extends Exception {
|
||||
|
||||
public ServerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ServerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ServerException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
protected ServerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.github.paperspigot.exception;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.ThrownExpBottle;
|
||||
import org.github.paperspigot.event.ServerExceptionEvent;
|
||||
|
||||
/**
|
||||
* Thrown when the internal server throws a recoverable exception.
|
||||
*/
|
||||
public class ServerInternalException extends ServerException {
|
||||
|
||||
public ServerInternalException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ServerInternalException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ServerInternalException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
protected ServerInternalException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
public static void reportInternalException(Throwable cause) {
|
||||
try {
|
||||
Bukkit.getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(cause)));;
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace(); // Don't want to rethrow!
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.github.paperspigot.exception;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Thrown whenever there is an exception with any enabling or disabling of plugins.
|
||||
*/
|
||||
public class ServerPluginEnableDisableException extends ServerPluginException {
|
||||
public ServerPluginEnableDisableException(String message, Throwable cause, Plugin responsiblePlugin) {
|
||||
super(message, cause, responsiblePlugin);
|
||||
}
|
||||
|
||||
public ServerPluginEnableDisableException(Throwable cause, Plugin responsiblePlugin) {
|
||||
super(cause, responsiblePlugin);
|
||||
}
|
||||
|
||||
protected ServerPluginEnableDisableException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) {
|
||||
super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin);
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.github.paperspigot.exception;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Wrapper exception for all cases to which a plugin can be immediately blamed for
|
||||
*/
|
||||
public class ServerPluginException extends ServerException {
|
||||
public ServerPluginException(String message, Throwable cause, Plugin responsiblePlugin) {
|
||||
super(message, cause);
|
||||
this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin");
|
||||
}
|
||||
|
||||
public ServerPluginException(Throwable cause, Plugin responsiblePlugin) {
|
||||
super(cause);
|
||||
this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin");
|
||||
}
|
||||
|
||||
protected ServerPluginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
this.responsiblePlugin = checkNotNull(responsiblePlugin, "responsiblePlugin");
|
||||
}
|
||||
|
||||
private final Plugin responsiblePlugin;
|
||||
|
||||
/**
|
||||
* Gets the plugin which is directly responsible for the exception being thrown
|
||||
*
|
||||
* @return plugin which is responsible for the exception throw
|
||||
*/
|
||||
public Plugin getResponsiblePlugin() {
|
||||
return responsiblePlugin;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package org.github.paperspigot.exception;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Thrown when an incoming plugin message channel throws an exception
|
||||
*/
|
||||
public class ServerPluginMessageException extends ServerPluginException {
|
||||
|
||||
private final Player player;
|
||||
private final String channel;
|
||||
private final byte[] data;
|
||||
|
||||
public ServerPluginMessageException(String message, Throwable cause, Plugin responsiblePlugin, Player player, String channel, byte[] data) {
|
||||
super(message, cause, responsiblePlugin);
|
||||
this.player = checkNotNull(player, "player");
|
||||
this.channel = checkNotNull(channel, "channel");
|
||||
this.data = checkNotNull(data, "data");
|
||||
}
|
||||
|
||||
public ServerPluginMessageException(Throwable cause, Plugin responsiblePlugin, Player player, String channel, byte[] data) {
|
||||
super(cause, responsiblePlugin);
|
||||
this.player = checkNotNull(player, "player");
|
||||
this.channel = checkNotNull(channel, "channel");
|
||||
this.data = checkNotNull(data, "data");
|
||||
}
|
||||
|
||||
protected ServerPluginMessageException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Plugin responsiblePlugin, Player player, String channel, byte[] data) {
|
||||
super(message, cause, enableSuppression, writableStackTrace, responsiblePlugin);
|
||||
this.player = checkNotNull(player, "player");
|
||||
this.channel = checkNotNull(channel, "channel");
|
||||
this.data = checkNotNull(data, "data");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the channel to which the error occurred from recieving data from
|
||||
* @return exception channel
|
||||
*/
|
||||
public String getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data to which the error occurred from
|
||||
* @return exception data
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player which the plugin message causing the exception originated from
|
||||
* @return exception player
|
||||
*/
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package org.github.paperspigot.exception;
|
||||
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Thrown when a plugin's scheduler fails with an exception
|
||||
*/
|
||||
public class ServerSchedulerException extends ServerPluginException {
|
||||
|
||||
private final BukkitTask task;
|
||||
|
||||
public ServerSchedulerException(String message, Throwable cause, BukkitTask task) {
|
||||
super(message, cause, task.getOwner());
|
||||
this.task = checkNotNull(task, "task");
|
||||
}
|
||||
|
||||
public ServerSchedulerException(Throwable cause, BukkitTask task) {
|
||||
super(cause, task.getOwner());
|
||||
this.task = checkNotNull(task, "task");
|
||||
}
|
||||
|
||||
protected ServerSchedulerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, BukkitTask task) {
|
||||
super(message, cause, enableSuppression, writableStackTrace, task.getOwner());
|
||||
this.task = checkNotNull(task, "task");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the task which threw the exception
|
||||
* @return exception throwing task
|
||||
*/
|
||||
public BukkitTask getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.github.paperspigot.exception;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
/**
|
||||
* Called when a tab-complete request throws an exception
|
||||
*/
|
||||
public class ServerTabCompleteException extends ServerCommandException {
|
||||
|
||||
public ServerTabCompleteException(String message, Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
|
||||
super(message, cause, command, commandSender, arguments);
|
||||
}
|
||||
|
||||
public ServerTabCompleteException(Throwable cause, Command command, CommandSender commandSender, String[] arguments) {
|
||||
super(cause, command, commandSender, arguments);
|
||||
}
|
||||
|
||||
protected ServerTabCompleteException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, Command command, CommandSender commandSender, String[] arguments) {
|
||||
super(message, cause, enableSuppression, writableStackTrace, command, commandSender, arguments);
|
||||
}
|
||||
}
|
@ -95,7 +95,7 @@
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.14</version>
|
||||
<version>8.0.29</version>
|
||||
<type>jar</type>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@ -143,6 +143,12 @@
|
||||
<artifactId>zstd-jni</artifactId>
|
||||
<version>1.5.2-3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.17.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- required until fixed plexus-compiler-eclipse is deployed -->
|
||||
|
@ -165,11 +165,7 @@ public class Block {
|
||||
}
|
||||
|
||||
public int toLegacyData(IBlockData iblockdata) {
|
||||
if (iblockdata != null && !iblockdata.a().isEmpty()) {
|
||||
throw new IllegalArgumentException("Don\'t know how to convert " + iblockdata + " back into data...");
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0; // Sportpaper - optimize toLegacyData removing unneeded sanity checks
|
||||
}
|
||||
|
||||
public IBlockData updateState(IBlockData iblockdata, IBlockAccess iblockaccess, BlockPosition blockposition) {
|
||||
|
@ -0,0 +1,88 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BlockCarpet extends Block {
|
||||
|
||||
public static final BlockStateEnum<EnumColor> COLOR = BlockStateEnum.of("color", EnumColor.class);
|
||||
|
||||
protected BlockCarpet() {
|
||||
super(Material.WOOL);
|
||||
this.j(this.blockStateList.getBlockData().set(BlockCarpet.COLOR, EnumColor.WHITE));
|
||||
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.0625F, 1.0F);
|
||||
this.a(true);
|
||||
this.a(CreativeModeTab.c);
|
||||
this.b(0);
|
||||
}
|
||||
|
||||
public MaterialMapColor g(IBlockData iblockdata) {
|
||||
return iblockdata.get(BlockCarpet.COLOR).e();
|
||||
}
|
||||
|
||||
public boolean c() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean d() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void j() {
|
||||
this.b(0);
|
||||
}
|
||||
|
||||
public void updateShape(IBlockAccess iblockaccess, BlockPosition blockposition) {
|
||||
this.b(0);
|
||||
}
|
||||
|
||||
protected void b(int i) {
|
||||
this.a(0.0F, 0.0F, 0.0F, 1.0F, 0.0625F, 1.0F);
|
||||
}
|
||||
|
||||
// SportPaper start - No height on carpet in feet height, avoid 1.7 players glitching
|
||||
public void a(World world, BlockPosition blockposition, IBlockData iblockdata, AxisAlignedBB axisalignedbb, List<AxisAlignedBB> list, Entity entity) {
|
||||
if (entity instanceof EntityHuman && blockposition.getY() == (int) entity.getBoundingBox().b) {
|
||||
return;
|
||||
}
|
||||
super.a(world, blockposition, iblockdata, axisalignedbb, list, entity);
|
||||
}
|
||||
// SportPaper end
|
||||
|
||||
public boolean canPlace(World world, BlockPosition blockposition) {
|
||||
return super.canPlace(world, blockposition) && this.e(world, blockposition);
|
||||
}
|
||||
|
||||
public void doPhysics(World world, BlockPosition blockposition, IBlockData iblockdata, Block block) {
|
||||
this.e(world, blockposition, iblockdata);
|
||||
}
|
||||
|
||||
private boolean e(World world, BlockPosition blockposition, IBlockData iblockdata) {
|
||||
if (!this.e(world, blockposition)) {
|
||||
this.b(world, blockposition, iblockdata, 0);
|
||||
world.setAir(blockposition);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean e(World world, BlockPosition blockposition) {
|
||||
return !world.isEmpty(blockposition.down());
|
||||
}
|
||||
|
||||
public int getDropData(IBlockData iblockdata) {
|
||||
return iblockdata.get(BlockCarpet.COLOR).getColorIndex();
|
||||
}
|
||||
|
||||
public IBlockData fromLegacyData(int i) {
|
||||
return this.getBlockData().set(BlockCarpet.COLOR, EnumColor.fromColorIndex(i));
|
||||
}
|
||||
|
||||
public int toLegacyData(IBlockData iblockdata) {
|
||||
return iblockdata.get(BlockCarpet.COLOR).getColorIndex();
|
||||
}
|
||||
|
||||
protected BlockStateList getStateList() {
|
||||
return new BlockStateList(this, BlockCarpet.COLOR);
|
||||
}
|
||||
}
|
@ -176,6 +176,7 @@ public class BlockFire extends Block {
|
||||
}
|
||||
|
||||
BlockPosition blockposition1 = blockposition.a(j, l, k);
|
||||
if (!world.isLoaded(blockposition1)) continue; // Paper
|
||||
int j1 = this.m(world, blockposition1);
|
||||
|
||||
if (j1 > 0) {
|
||||
@ -244,10 +245,13 @@ public class BlockFire extends Block {
|
||||
}
|
||||
|
||||
private void a(World world, BlockPosition blockposition, int i, Random random, int j) {
|
||||
// Paper start
|
||||
final IBlockData iblockdata = world.getTypeIfLoaded(blockposition);
|
||||
if (iblockdata == null) return;
|
||||
int k = this.c(world.getType(blockposition).getBlock());
|
||||
|
||||
if (random.nextInt(i) < k) {
|
||||
IBlockData iblockdata = world.getType(blockposition);
|
||||
//IBlockData iblockdata = world.getType(blockposition); // Paper
|
||||
|
||||
// CraftBukkit start
|
||||
org.bukkit.block.Block theBlock = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
|
||||
@ -300,7 +304,11 @@ public class BlockFire extends Block {
|
||||
EnumDirection[] aenumdirection = EnumDirection.values();
|
||||
int j = aenumdirection.length;
|
||||
|
||||
for (EnumDirection enumdirection : aenumdirection) {
|
||||
for (int k = 0; k < j; ++k) {
|
||||
EnumDirection enumdirection = aenumdirection[k];
|
||||
|
||||
final IBlockData type = world.getTypeIfLoaded(blockposition.shift(enumdirection)); // Paper
|
||||
if (type == null) continue; // Paper
|
||||
i = Math.max(this.d(world.getType(blockposition.shift(enumdirection)).getBlock()), i);
|
||||
}
|
||||
|
||||
|
@ -107,6 +107,7 @@ public class BlockFlowing extends BlockFluids {
|
||||
|
||||
if (this.h(world, blockposition.down(), iblockdata2)) {
|
||||
// CraftBukkit start - Send "down" to the server
|
||||
if (!canFlowTo(world, source, BlockFace.DOWN)) { return; } // Paper
|
||||
BlockFromToEvent event = new BlockFromToEvent(source, BlockFace.DOWN);
|
||||
if (server != null) {
|
||||
server.getPluginManager().callEvent(event);
|
||||
@ -141,6 +142,8 @@ public class BlockFlowing extends BlockFluids {
|
||||
EnumDirection enumdirection1 = (EnumDirection) value;
|
||||
|
||||
// CraftBukkit start
|
||||
if(this.h(world, blockposition.shift(enumdirection1), world.getType(blockposition.shift(enumdirection1)))) {
|
||||
if (!canFlowTo(world, source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection1))) { continue; } // Paper
|
||||
BlockFromToEvent event = new BlockFromToEvent(source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection1));
|
||||
if (server != null) {
|
||||
server.getPluginManager().callEvent(event);
|
||||
@ -149,14 +152,21 @@ public class BlockFlowing extends BlockFluids {
|
||||
if (!event.isCancelled()) {
|
||||
this.flow(world, blockposition.shift(enumdirection1), world.getType(blockposition.shift(enumdirection1)), k);
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Paper start
|
||||
private boolean canFlowTo(World world, org.bukkit.block.Block source, BlockFace face) {
|
||||
return source.getWorld().isChunkLoaded((source.getX() + face.getModX()) >> 4, (source.getZ() + face.getModZ()) >> 4);
|
||||
}
|
||||
// Paper end
|
||||
|
||||
private void flow(World world, BlockPosition blockposition, IBlockData iblockdata, int i) {
|
||||
if (world.isLoaded(blockposition) && this.h(world, blockposition, iblockdata)) { // CraftBukkit - add isLoaded check
|
||||
if (/*world.isLoaded(blockposition) &&*/ this.h(world, blockposition, iblockdata)) { // CraftBukkit - add isLoaded check // Paper - Already checked before we get here for isLoade
|
||||
if (iblockdata.getBlock() != Blocks.AIR) {
|
||||
if (this.material == Material.LAVA) {
|
||||
this.fizz(world, blockposition);
|
||||
|
@ -117,13 +117,13 @@ public class BlockPiston extends Block {
|
||||
}
|
||||
|
||||
public boolean a(World world, BlockPosition blockposition, IBlockData iblockdata, int i, int j) {
|
||||
EnumDirection enumdirection = iblockdata.get(BlockPiston.FACING);
|
||||
EnumDirection enumdirection = (EnumDirection) iblockdata.get(BlockPiston.FACING);
|
||||
|
||||
if (!world.isClientSide) {
|
||||
boolean flag = this.a(world, blockposition, enumdirection);
|
||||
|
||||
if (flag && i == 1) {
|
||||
world.setTypeAndData(blockposition, iblockdata.set(BlockPiston.EXTENDED, Boolean.TRUE), 2);
|
||||
world.setTypeAndData(blockposition, iblockdata.set(BlockPiston.EXTENDED, Boolean.valueOf(true)), 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -133,11 +133,15 @@ public class BlockPiston extends Block {
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
// SportBukkit start
|
||||
org.bukkit.event.block.BlockPistonEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPistonEvent(world, blockposition, enumdirection, true);
|
||||
if(event != null && event.isCancelled()) return false;
|
||||
// SportBukkit end
|
||||
if (!this.a(world, blockposition, enumdirection, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
world.setTypeAndData(blockposition, iblockdata.set(BlockPiston.EXTENDED, Boolean.TRUE), 2);
|
||||
world.setTypeAndData(blockposition, iblockdata.set(BlockPiston.EXTENDED, Boolean.valueOf(true)), 2);
|
||||
world.makeSound((double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, "tile.piston.out", 0.5F, world.random.nextFloat() * 0.25F + 0.6F);
|
||||
} else if (i == 1) {
|
||||
TileEntity tileentity = world.getTileEntity(blockposition.shift(enumdirection));
|
||||
@ -148,6 +152,10 @@ public class BlockPiston extends Block {
|
||||
|
||||
world.setTypeAndData(blockposition, Blocks.PISTON_EXTENSION.getBlockData().set(BlockPistonMoving.FACING, enumdirection).set(BlockPistonMoving.TYPE, this.sticky ? BlockPistonExtension.EnumPistonType.STICKY : BlockPistonExtension.EnumPistonType.DEFAULT), 3);
|
||||
world.setTileEntity(blockposition, BlockPistonMoving.a(this.fromLegacyData(j), enumdirection, false, true));
|
||||
// SportBukkit start
|
||||
org.bukkit.event.block.BlockPistonEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPistonEvent(world, blockposition, enumdirection, false);
|
||||
if(event != null && event.isCancelled()) return false;
|
||||
// SportBukkit end
|
||||
if (this.sticky) {
|
||||
BlockPosition blockposition1 = blockposition.a(enumdirection.getAdjacentX() * 2, enumdirection.getAdjacentY() * 2, enumdirection.getAdjacentZ() * 2);
|
||||
Block block = world.getType(blockposition1).getBlock();
|
||||
|
@ -18,6 +18,7 @@ import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.google.common.collect.Lists; // CraftBukkit
|
||||
import org.bukkit.Bukkit; // CraftBukkit
|
||||
import org.bukkit.craftbukkit.util.LongHash;
|
||||
|
||||
public class Chunk {
|
||||
|
||||
@ -29,6 +30,7 @@ public class Chunk {
|
||||
private boolean h;
|
||||
public final World world;
|
||||
public final int[] heightMap;
|
||||
public final long chunkKey; // Paper
|
||||
public final int locX;
|
||||
public final int locZ;
|
||||
private boolean k;
|
||||
@ -42,7 +44,7 @@ public class Chunk {
|
||||
private boolean done;
|
||||
private boolean lit;
|
||||
private boolean p;
|
||||
public boolean q;
|
||||
public boolean q; public void markDirty() { this.q = true; }// Paper
|
||||
private boolean r;
|
||||
private long lastSaved;
|
||||
private int t;
|
||||
@ -155,6 +157,7 @@ public class Chunk {
|
||||
this.world = world;
|
||||
this.locX = i;
|
||||
this.locZ = j;
|
||||
this.chunkKey = LongHash.toLong(this.locX, this.locZ); // Paper
|
||||
this.heightMap = new int[256];
|
||||
|
||||
for (int k = 0; k < this.entitySlices.length; ++k) {
|
||||
@ -843,6 +846,7 @@ public class Chunk {
|
||||
return !block.isTileEntity() ? null : ((IContainer) block).a(this.world, this.c(blockposition));
|
||||
}
|
||||
|
||||
public final TileEntity getTileEntityImmediately(BlockPosition pos) { return this.a(pos, EnumTileEntityState.IMMEDIATE); } // Paper - OBFHELPER
|
||||
public TileEntity a(BlockPosition blockposition, Chunk.EnumTileEntityState chunk_enumtileentitystate) {
|
||||
// CraftBukkit start
|
||||
TileEntity tileentity = null;
|
||||
@ -899,9 +903,16 @@ public class Chunk {
|
||||
System.out.println("Chunk coordinates: " + (this.locX * 16) + "," + (this.locZ * 16));
|
||||
new Exception().printStackTrace();
|
||||
// CraftBukkit end
|
||||
|
||||
if (this.world.paperSpigotConfig.removeCorruptTEs) {
|
||||
this.removeTileEntity(tileentity.getPosition());
|
||||
this.markDirty();
|
||||
org.bukkit.Bukkit.getLogger().info("Removing corrupt tile entity");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTileEntity(BlockPosition blockposition) { this.e(blockposition); } // Paper - OBFHELPER
|
||||
public void e(BlockPosition blockposition) {
|
||||
if (this.h) {
|
||||
TileEntity tileentity = this.tileEntities.remove(blockposition);
|
||||
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.*;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@ -16,38 +17,39 @@ import org.bukkit.craftbukkit.util.LongHash;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
// CraftBukkit end
|
||||
// TacoSpigot start
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongArraySet;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
|
||||
// TacoSpigot end
|
||||
|
||||
public class ChunkProviderServer implements IChunkProvider {
|
||||
|
||||
private static final Logger b = LogManager.getLogger();
|
||||
public LongSet unloadQueue = new LongArraySet(); // CraftBukkit - LongHashSet // TacoSpigot - LongHashSet -> HashArraySet
|
||||
public LongSet unloadQueue = new LongOpenHashSet(20); // CraftBukkit - LongHashSet // TacoSpigot - LongHashSet -> HashArraySet
|
||||
public Chunk emptyChunk;
|
||||
public IChunkProvider chunkProvider;
|
||||
public IChunkLoader chunkLoader; // KigPaper - private -> public
|
||||
public boolean forceChunkLoad = false; // CraftBukkit - true -> false
|
||||
public Long2ObjectMap<Chunk> chunks = new Long2ObjectOpenHashMap<>(4096, 0.5f); // TacoSpigot - use trove Long2ObjectOpenHashMap instead of craftbukkit implementation (using inital capacity and load factor chosen by Amaranth in an old impl)
|
||||
// Paper start
|
||||
protected Chunk lastChunkByPos = null;
|
||||
public Long2ObjectMap<Chunk> chunks = new Long2ObjectOpenHashMap<Chunk>(8192, 0.5f) {
|
||||
@Override
|
||||
public Chunk get(long key) {
|
||||
if (lastChunkByPos != null && key == lastChunkByPos.chunkKey) {
|
||||
return lastChunkByPos;
|
||||
}
|
||||
return lastChunkByPos = super.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk remove(long key) {
|
||||
if (lastChunkByPos != null && key == lastChunkByPos.chunkKey) {
|
||||
lastChunkByPos = null;
|
||||
}
|
||||
return super.remove(key);
|
||||
}
|
||||
}; // CraftBukkit
|
||||
// Paper end
|
||||
public WorldServer world;
|
||||
|
||||
// Migot start
|
||||
private ChunkRegionLoader checkedRegionLoader = null;
|
||||
|
||||
public boolean doesChunkExist(int x, int z) {
|
||||
if(this.checkedRegionLoader == null && this.chunkLoader instanceof ChunkRegionLoader) {
|
||||
this.checkedRegionLoader = (ChunkRegionLoader) this.chunkLoader;
|
||||
}
|
||||
if(this.checkedRegionLoader != null) {
|
||||
return this.checkedRegionLoader.chunkExists(this.world, x, z);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Migot end
|
||||
|
||||
public ChunkProviderServer(WorldServer worldserver, IChunkLoader ichunkloader, IChunkProvider ichunkprovider) {
|
||||
this.emptyChunk = new EmptyChunk(worldserver, Integer.MIN_VALUE, Integer.MIN_VALUE); // Migot
|
||||
this.world = worldserver;
|
||||
@ -126,7 +128,6 @@ public class ChunkProviderServer implements IChunkProvider {
|
||||
}
|
||||
|
||||
public Chunk getChunkAt(int i, int j, Runnable runnable) {
|
||||
unloadQueue.remove(LongHash.toLong(i, j)); // TacoSpigot - directly invoke LongHash
|
||||
Chunk chunk = chunks.get(LongHash.toLong(i, j));
|
||||
ChunkRegionLoader loader = null;
|
||||
|
||||
@ -146,6 +147,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||||
chunk = originalGetChunkAt(i, j);
|
||||
}
|
||||
|
||||
unloadQueue.remove(LongHash.toLong(i, j)); // SportPaper
|
||||
// If we didn't load the chunk async and have a callback run it now
|
||||
if (runnable != null) {
|
||||
runnable.run();
|
||||
@ -154,7 +156,6 @@ public class ChunkProviderServer implements IChunkProvider {
|
||||
return chunk;
|
||||
}
|
||||
public Chunk originalGetChunkAt(int i, int j) {
|
||||
this.unloadQueue.remove(LongHash.toLong(i, j)); // TacoSpigot - directly invoke LongHash
|
||||
Chunk chunk = this.chunks.get(LongHash.toLong(i, j));
|
||||
boolean newChunk = false;
|
||||
// CraftBukkit end
|
||||
@ -215,6 +216,7 @@ public class ChunkProviderServer implements IChunkProvider {
|
||||
world.timings.syncChunkLoadTimer.stopTiming(); // Spigot
|
||||
}
|
||||
|
||||
this.unloadQueue.remove(LongHash.toLong(i, j)); // SportPaper
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@ -365,33 +367,31 @@ public class ChunkProviderServer implements IChunkProvider {
|
||||
|
||||
}
|
||||
|
||||
public boolean unloadChunks() {
|
||||
if (!this.world.savingDisabled) {
|
||||
// CraftBukkit start
|
||||
Server server = this.world.getServer();
|
||||
// TacoSpigot start - use iterator for unloadQueue
|
||||
LongIterator iterator = unloadQueue.iterator();
|
||||
for (int i = 0; i < 100 && iterator.hasNext(); ++i) {
|
||||
long chunkcoordinates = iterator.next();
|
||||
iterator.remove();
|
||||
// TacoSpigot end
|
||||
Chunk chunk = this.chunks.get(chunkcoordinates);
|
||||
if (chunk == null) continue;
|
||||
// SportPaper start
|
||||
public void unloadAllChunks() {
|
||||
for(Chunk chunk : chunks.values()) {
|
||||
unloadChunk(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public void unloadChunk(Chunk chunk) {
|
||||
unloadChunk(chunk, false);
|
||||
}
|
||||
|
||||
private void unloadChunk(Chunk chunk, boolean auto) {
|
||||
Server server = this.world.getServer();
|
||||
ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk);
|
||||
server.getPluginManager().callEvent(event);
|
||||
if (!event.isCancelled()) {
|
||||
|
||||
if (chunk != null) {
|
||||
chunk.markAsUnloaded(); // Migot
|
||||
chunk.removeEntities();
|
||||
this.saveChunk(chunk);
|
||||
this.saveChunkNOP(chunk);
|
||||
this.chunks.remove(chunkcoordinates); // CraftBukkit
|
||||
this.chunks.remove(chunk.chunkKey); // CraftBukkit
|
||||
if (!auto && this.unloadQueue.contains(chunk.chunkKey)) {
|
||||
this.unloadQueue.remove(chunk.chunkKey);
|
||||
}
|
||||
|
||||
// this.unloadQueue.remove(olong);
|
||||
|
||||
// Update neighbor counts
|
||||
for (int x = -2; x < 3; x++) {
|
||||
for (int z = -2; z < 3; z++) {
|
||||
@ -408,6 +408,22 @@ public class ChunkProviderServer implements IChunkProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
// SportPaper end
|
||||
|
||||
public boolean unloadChunks() {
|
||||
if (!this.world.savingDisabled) {
|
||||
// CraftBukkit start
|
||||
Server server = this.world.getServer();
|
||||
// SportPaper start
|
||||
LongIterator iterator = unloadQueue.iterator();
|
||||
for (int i = 0; i < 100 && iterator.hasNext(); ++i) {
|
||||
long chunkcoordinates = iterator.nextLong();
|
||||
iterator.remove();
|
||||
// SportPaper end
|
||||
Chunk chunk = this.chunks.get(chunkcoordinates);
|
||||
if (chunk == null) continue;
|
||||
unloadChunk(chunk, true); // SportPaper - Move to own method
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (this.chunkLoader != null) {
|
||||
|
@ -8,6 +8,7 @@ import java.net.InetAddress;
|
||||
import java.net.Proxy;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -28,7 +29,7 @@ import org.bukkit.event.server.RemoteServerCommandEvent;
|
||||
public class DedicatedServer extends MinecraftServer implements IMinecraftServer {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final List<ServerCommand> l = Collections.synchronizedList(Lists.<ServerCommand>newArrayList()); // CraftBukkit - fix decompile error
|
||||
private final Queue<ServerCommand> l = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Paper - use a proper queue
|
||||
private RemoteStatusListener m;
|
||||
private RemoteControlListener n;
|
||||
public PropertyManager propertyManager;
|
||||
@ -374,7 +375,7 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
|
||||
|
||||
public void B() { // CraftBukkit - fix decompile error
|
||||
super.B();
|
||||
this.aO();
|
||||
// this.aO(); // SportBukkit - moved to processTasks()
|
||||
}
|
||||
|
||||
public boolean getAllowNether() {
|
||||
@ -399,10 +400,21 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
|
||||
this.l.add(new ServerCommand(s, icommandlistener));
|
||||
}
|
||||
|
||||
// SportBukkit start
|
||||
@Override
|
||||
protected void processTasks() {
|
||||
super.processTasks();
|
||||
processCommands();
|
||||
}
|
||||
// SportBukkit end
|
||||
public void processCommands() { aO(); } // SportBukkit - alias
|
||||
|
||||
public void aO() {
|
||||
SpigotTimings.serverCommandTimer.startTiming(); // Spigot
|
||||
while (!this.l.isEmpty()) {
|
||||
ServerCommand servercommand = this.l.remove(0);
|
||||
// Paper start - use proper queue
|
||||
ServerCommand servercommand;
|
||||
while ((servercommand = this.l.poll()) != null) {
|
||||
// Paper end
|
||||
|
||||
// CraftBukkit start - ServerCommand for preprocessing
|
||||
ServerCommandEvent event = new ServerCommandEvent(console, servercommand.command);
|
||||
@ -652,7 +664,7 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer
|
||||
return RemoteControlCommandListener.getInstance().j();
|
||||
}
|
||||
};
|
||||
processQueue.add(waitable);
|
||||
addMainThreadTask(waitable);
|
||||
try {
|
||||
return waitable.get();
|
||||
} catch (java.util.concurrent.ExecutionException e) {
|
||||
|
@ -17,6 +17,7 @@ import org.bukkit.entity.Painting;
|
||||
import org.bukkit.entity.Vehicle;
|
||||
import co.aikar.timings.SpigotTimings; // Spigot
|
||||
import co.aikar.timings.Timing; // Spigot
|
||||
import org.bukkit.event.entity.EntityCombustByBlockEvent;
|
||||
import org.bukkit.event.entity.EntityCombustByEntityEvent;
|
||||
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
|
||||
import org.bukkit.event.painting.PaintingBreakByEntityEvent;
|
||||
@ -50,7 +51,7 @@ public abstract class Entity implements ICommandListener {
|
||||
private static int entityCount = 1;
|
||||
private int id;
|
||||
public double j;
|
||||
public boolean k;
|
||||
public boolean k; public boolean blocksEntitySpawning() { return k; } // Paper - OBFHELPER
|
||||
public Entity passenger;
|
||||
public Entity vehicle;
|
||||
public boolean attachedToPlayer;
|
||||
@ -94,6 +95,7 @@ public abstract class Entity implements ICommandListener {
|
||||
public int ticksLived;
|
||||
public int maxFireTicks;
|
||||
public int fireTicks;
|
||||
public boolean wasOnFire; // CraftBukkit - to detect when the fire goes out
|
||||
public boolean inWater; // Spigot - protected -> public // PAIL
|
||||
public int noDamageTicks;
|
||||
protected boolean justCreated;
|
||||
@ -117,7 +119,7 @@ public abstract class Entity implements ICommandListener {
|
||||
public boolean ah;
|
||||
public boolean ai;
|
||||
public int portalCooldown;
|
||||
protected boolean ak;
|
||||
protected boolean ak; public boolean inPortal() { return ak; } // Paper - OBFHELPER
|
||||
|
||||
protected int al;
|
||||
public int dimension;
|
||||
@ -394,22 +396,24 @@ public abstract class Entity implements ICommandListener {
|
||||
this.damageEntity(DamageSource.LAVA, 4.0F);
|
||||
|
||||
// CraftBukkit start - Fallen in lava TODO: this event spams!
|
||||
Vec3D lavaPos = this.world.getLargestBlockIntersection(this.boundingBox.shrink(0.001D, 0.001D, 0.001D), Material.LAVA);
|
||||
org.bukkit.block.Block lavaBlock = lavaPos == null ? null : this.world.getWorld().getBlockAt((int) lavaPos.a, (int) lavaPos.b, (int) lavaPos.c);
|
||||
try {
|
||||
CraftEventFactory.blockDamage = lavaBlock;
|
||||
this.damageEntity(DamageSource.LAVA, 4);
|
||||
} finally {
|
||||
CraftEventFactory.blockDamage = null;
|
||||
}
|
||||
if (this instanceof EntityLiving) {
|
||||
if (fireTicks <= 0) {
|
||||
// not on fire yet
|
||||
// TODO: shouldn't be sending null for the block
|
||||
org.bukkit.block.Block damager = null; // ((WorldServer) this.l).getWorld().getBlockAt(i, j, k);
|
||||
// Note that in order for cancelling or custom duration to work properly,
|
||||
// this event must be fired every tick, thus we cannot avoid "spamming" it.
|
||||
org.bukkit.entity.Entity damagee = this.getBukkitEntity();
|
||||
EntityCombustEvent combustEvent = new org.bukkit.event.entity.EntityCombustByBlockEvent(damager, damagee, 15);
|
||||
EntityCombustEvent combustEvent = new org.bukkit.event.entity.EntityCombustByBlockEvent(lavaBlock, damagee, 15);
|
||||
this.world.getServer().getPluginManager().callEvent(combustEvent);
|
||||
|
||||
if (!combustEvent.isCancelled()) {
|
||||
this.setOnFire(combustEvent.getDuration());
|
||||
}
|
||||
} else {
|
||||
// This will be called every single tick the entity is in lava, so don't throw an event
|
||||
this.setOnFire(15);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end - we also don't throw an event unless the object in lava is living, to save on some event calls
|
||||
@ -802,21 +806,32 @@ public abstract class Entity implements ICommandListener {
|
||||
|
||||
boolean flag2 = this.U();
|
||||
|
||||
if (this.world.e(this.getBoundingBox().shrink(0.001D, 0.001D, 0.001D))) {
|
||||
// CraftBukkit start - get the location of the fire block
|
||||
Vec3D firePos = this.world.getLargestBlockIntersection(this.boundingBox.shrink(0.001D, 0.001D, 0.001D), Material.FIRE);
|
||||
if (firePos != null) {
|
||||
org.bukkit.block.Block fireBlock = this.bukkitEntity.getWorld().getBlockAt((int) firePos.a, (int) firePos.b, (int) firePos.c);
|
||||
try {
|
||||
CraftEventFactory.blockDamage = fireBlock;
|
||||
this.burn(1);
|
||||
} finally {
|
||||
CraftEventFactory.blockDamage = null;
|
||||
}
|
||||
if (!flag2) {
|
||||
++this.fireTicks;
|
||||
// CraftBukkit start - Not on fire yet
|
||||
if (this.fireTicks <= 0) { // Only throw events on the first combust, otherwise it spams
|
||||
EntityCombustEvent event = new EntityCombustEvent(getBukkitEntity(), 8);
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
EntityCombustByBlockEvent event = new EntityCombustByBlockEvent(fireBlock, this.getBukkitEntity(), 8);
|
||||
this.world.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
setOnFire(event.getDuration());
|
||||
// Note carefully how this works: when fireTicks is negative, the entity is
|
||||
// "heating up" but not on fire yet. When fireTicks reaches 0, the entity
|
||||
// "ignites" and fireTicks jumps to 160. It will then stay at that value as
|
||||
// long as the player remains in fire (because the ++ below will cancel out
|
||||
// the -- in the entity tick). For the event cancelling to work, it has to
|
||||
// be fired every tick, thus we cannot avoid "spamming" it.
|
||||
++this.fireTicks;
|
||||
if (this.fireTicks == 0) {
|
||||
this.setOnFire(event.getDuration());
|
||||
}
|
||||
} else {
|
||||
// CraftBukkit end
|
||||
this.setOnFire(8);
|
||||
|
||||
}
|
||||
}
|
||||
} else if (this.fireTicks <= 0) {
|
||||
@ -828,6 +843,14 @@ public abstract class Entity implements ICommandListener {
|
||||
this.fireTicks = -this.maxFireTicks;
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
if(this.fireTicks > 0) {
|
||||
this.wasOnFire = true;
|
||||
} else if(this.wasOnFire && this.fireTicks <= 0) {
|
||||
this.wasOnFire = false;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
this.world.methodProfiler.b();
|
||||
}
|
||||
}
|
||||
@ -1139,6 +1162,7 @@ public abstract class Entity implements ICommandListener {
|
||||
this.lastYaw -= 360.0F;
|
||||
}
|
||||
|
||||
world.getChunkAt((int) Math.floor(this.locX) >> 4, (int) Math.floor(this.locZ) >> 4); // Paper - ensure chunk is always loaded
|
||||
this.setPosition(this.locX, this.locY, this.locZ);
|
||||
this.setYawPitch(f, f1);
|
||||
}
|
||||
@ -2082,7 +2106,7 @@ public abstract class Entity implements ICommandListener {
|
||||
}
|
||||
|
||||
public void teleportTo(Location exit, boolean portal) {
|
||||
if (true) {
|
||||
if (!this.dead) { // Paper
|
||||
WorldServer worldserver = ((CraftWorld) getBukkitEntity().getLocation().getWorld()).getHandle();
|
||||
WorldServer worldserver1 = ((CraftWorld) exit.getWorld()).getHandle();
|
||||
// CraftBukkit end
|
||||
|
@ -11,6 +11,7 @@ import org.bukkit.event.player.PlayerPickupItemEvent;
|
||||
import net.techcable.tacospigot.event.entity.ArrowCollideEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Arrow;
|
||||
import org.github.paperspigot.PaperSpigotConfig;
|
||||
// TacoSpigot end
|
||||
|
||||
public class EntityArrow extends Entity implements IProjectile {
|
||||
@ -101,7 +102,7 @@ public class EntityArrow extends Entity implements IProjectile {
|
||||
this.motX = -MathHelper.sin(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F);
|
||||
this.motZ = MathHelper.cos(this.yaw / 180.0F * 3.1415927F) * MathHelper.cos(this.pitch / 180.0F * 3.1415927F);
|
||||
this.motY = -MathHelper.sin(this.pitch / 180.0F * 3.1415927F);
|
||||
this.shoot(this.motX, this.motY, this.motZ, f * 1.5F, 1.0F);
|
||||
this.shoot(this.motX, this.motY, this.motZ, f * 1.5F, PaperSpigotConfig.includeRandomnessInArrowTrajectory ? 1.0F : 0); // SportPaper
|
||||
}
|
||||
|
||||
protected void h() {
|
||||
@ -114,9 +115,11 @@ public class EntityArrow extends Entity implements IProjectile {
|
||||
d0 /= f2;
|
||||
d1 /= f2;
|
||||
d2 /= f2;
|
||||
if (f1 != 0) {
|
||||
d0 += this.random.nextGaussian() * (double) (this.random.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double) f1;
|
||||
d1 += this.random.nextGaussian() * (double) (this.random.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double) f1;
|
||||
d2 += this.random.nextGaussian() * (double) (this.random.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double) f1;
|
||||
}
|
||||
d0 *= f;
|
||||
d1 *= f;
|
||||
d2 *= f;
|
||||
@ -248,7 +251,7 @@ public class EntityArrow extends Entity implements IProjectile {
|
||||
f2 = MathHelper.sqrt(this.motX * this.motX + this.motY * this.motY + this.motZ * this.motZ);
|
||||
int k = MathHelper.f((double) f2 * this.damage);
|
||||
|
||||
if (this.isCritical()) {
|
||||
if (this.isCritical() && PaperSpigotConfig.includeRandomnessInArrowDamage) { // SportPaper
|
||||
k += this.random.nextInt(k / 2 + 2);
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ public class EntityBoat extends Entity {
|
||||
this.world.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
// f = event.getDamage(); // TODO Why don't we do this?
|
||||
// CraftBukkit end
|
||||
|
@ -569,8 +569,12 @@ public class EntityEnderDragon extends EntityInsentient implements IComplex, IMo
|
||||
if (this.by == 1) {
|
||||
// CraftBukkit start - Use relative location for far away sounds
|
||||
// this.world.a(1018, new BlockPosition(this), 0);
|
||||
int viewDistance = this.world.getServer().getViewDistance() * 16;
|
||||
for (EntityPlayer player : MinecraftServer.getServer().getPlayerList().players) {
|
||||
// Paper start
|
||||
//int viewDistance = ((WorldServer) this.world).spigotConfig.viewDistance * 16; // Paper - updated to use worlds actual view distance incase we have to uncomment this due to removal of player view distance API
|
||||
for (EntityHuman human : world.players) {
|
||||
EntityPlayer player = (EntityPlayer) human;
|
||||
int viewDistance = player.viewDistance;
|
||||
// Paper end
|
||||
double deltaX = this.locX - player.locX;
|
||||
double deltaZ = this.locZ - player.locZ;
|
||||
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
|
||||
|
@ -361,6 +361,12 @@ public class EntityFishingHook extends Entity {
|
||||
this.motY *= f2;
|
||||
this.motZ *= f2;
|
||||
this.setPosition(this.locX, this.locY, this.locZ);
|
||||
|
||||
// Paper start - These shouldn't be going through portals
|
||||
if (this.inPortal()) {
|
||||
this.die();
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -853,6 +853,9 @@ public abstract class EntityHuman extends EntityLiving {
|
||||
public boolean a(EntityHuman entityhuman) {
|
||||
// CraftBukkit start - Change to check OTHER player's scoreboard team according to API
|
||||
// To summarize this method's logic, it's "Can parameter hurt this"
|
||||
|
||||
if(this == entityhuman) return true; // SportBukkit - self-damage is always allowed
|
||||
|
||||
org.bukkit.scoreboard.Team team;
|
||||
if (entityhuman instanceof EntityPlayer) {
|
||||
EntityPlayer thatPlayer = (EntityPlayer) entityhuman;
|
||||
|
@ -156,6 +156,10 @@ public class EntityItem extends Entity implements HopperPusher {
|
||||
// Spigot end
|
||||
|
||||
private void w() {
|
||||
// Paper start - avoid item merge if stack size above max stack size
|
||||
ItemStack stack = getItemStack();
|
||||
if (stack.count >= stack.getMaxStackSize()) return;
|
||||
// Paper end
|
||||
// Spigot start
|
||||
double radius = world.spigotConfig.itemMerge;
|
||||
// Spigot end
|
||||
|
@ -122,7 +122,7 @@ public abstract class EntityMinecartAbstract extends Entity implements INamableT
|
||||
this.world.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
f = (float) event.getDamage();
|
||||
|
@ -4,12 +4,8 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.elevatemc.spigot.eSpigot;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -31,13 +27,14 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
|
||||
private static final Logger bH = LogManager.getLogger();
|
||||
public String locale = "en_US"; // Spigot
|
||||
public long lastSave = MinecraftServer.currentTick; // Paper
|
||||
public PlayerConnection playerConnection;
|
||||
public final MinecraftServer server;
|
||||
public final PlayerInteractManager playerInteractManager;
|
||||
public double d;
|
||||
public double e;
|
||||
public final List<ChunkCoordIntPair> chunkCoordIntPairQueue = Lists.newLinkedList();
|
||||
public final List<Integer> removeQueue = Lists.newLinkedList();
|
||||
public final Deque<Integer> removeQueue = new ArrayDeque<>(); // Paper
|
||||
private final ServerStatisticManager bK;
|
||||
private float bL = Float.MIN_VALUE;
|
||||
private float bM = -1.0E8F;
|
||||
@ -127,6 +124,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
|
||||
public void a(NBTTagCompound nbttagcompound) {
|
||||
super.a(nbttagcompound);
|
||||
if (this.locY > 300) this.locY = 257; // Paper - bring down to a saner Y level if out of world
|
||||
if (nbttagcompound.hasKeyOfType("playerGameType", 99)) {
|
||||
if (MinecraftServer.getServer().getForceGamemode()) {
|
||||
this.playerInteractManager.setGameMode(MinecraftServer.getServer().getGamemode());
|
||||
@ -223,10 +221,11 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
Iterator iterator = this.removeQueue.iterator();
|
||||
int j = 0;
|
||||
|
||||
while (iterator.hasNext() && j < i) {
|
||||
aint[j++] = (Integer) iterator.next();
|
||||
iterator.remove();
|
||||
}
|
||||
// Paper start
|
||||
Integer integer;
|
||||
while (j < i && (integer = this.removeQueue.poll()) != null) {
|
||||
aint[j++] = integer.intValue();
|
||||
}// Paper end
|
||||
|
||||
this.playerConnection.sendPacket(new PacketPlayOutEntityDestroy(aint));
|
||||
}
|
||||
@ -423,7 +422,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
}
|
||||
}
|
||||
|
||||
IChatBaseComponent chatmessage = this.bs().b();
|
||||
IChatBaseComponent chatmessage = damagesource == DamageSource.GENERIC ? damagesource.getLocalizedDeathMessage(this) : this.bs().b(); // CraftBukkit
|
||||
|
||||
String deathmessage = chatmessage.c();
|
||||
org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage, keepInventory);
|
||||
@ -464,7 +463,8 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
|
||||
EntityLiving entityliving = this.bt();
|
||||
|
||||
if (entityliving != null) {
|
||||
// CraftBukkit - can't have a combat tracked killer with a generic damage source
|
||||
if (entityliving != null && damagesource != DamageSource.GENERIC) {
|
||||
EntityTypes.MonsterEggInfo entitytypes_monsteregginfo = EntityTypes.eggInfo.get(EntityTypes.a(entityliving));
|
||||
|
||||
if (entitytypes_monsteregginfo != null) {
|
||||
@ -488,7 +488,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
if (!flag && this.invulnerableTicks > 0 && damagesource != DamageSource.OUT_OF_WORLD) {
|
||||
return false;
|
||||
} else {
|
||||
if (damagesource instanceof EntityDamageSource) {
|
||||
if (damagesource instanceof EntityDamageSource && !damagesource.isExplosion()) { // SportBukkit - explosion damage is not subject to FF rules
|
||||
Entity entity = damagesource.getEntity();
|
||||
|
||||
if (entity instanceof EntityHuman && !this.a((EntityHuman) entity)) {
|
||||
@ -510,6 +510,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
}
|
||||
|
||||
public boolean a(EntityHuman entityhuman) {
|
||||
if(this == entityhuman) return true; // SportBukkit - self-damage is always allowed
|
||||
return this.cr() && super.a(entityhuman);
|
||||
}
|
||||
|
||||
@ -917,8 +918,11 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
this.lastSentExp = -1;
|
||||
this.bM = -1.0F;
|
||||
this.bN = -1;
|
||||
// Paper start - Optimize remove queue
|
||||
if (this.removeQueue != ((EntityPlayer) entityhuman).removeQueue) {
|
||||
this.removeQueue.addAll(((EntityPlayer) entityhuman).removeQueue);
|
||||
}
|
||||
}
|
||||
|
||||
protected void a(MobEffect mobeffect) {
|
||||
super.a(mobeffect);
|
||||
@ -1201,6 +1205,15 @@ public class EntityPlayer extends EntityHuman implements ICrafting {
|
||||
this.exp = 0;
|
||||
this.deathTicks = 0;
|
||||
this.removeAllEffects();
|
||||
|
||||
// Clear potion metadata now, because new effects might get added
|
||||
// before the update in the tick has a chance to run, and if they
|
||||
// match the old effects, the metadata will never be marked dirty
|
||||
// and will go out of sync with the client.
|
||||
this.datawatcher.watch(8, (byte) 0);
|
||||
this.datawatcher.watch(7, 0);
|
||||
this.setInvisible(false);
|
||||
|
||||
this.updateEffects = true;
|
||||
this.activeContainer = this.defaultContainer;
|
||||
this.killer = null;
|
||||
|
@ -153,7 +153,8 @@ public class EntityTrackerEntry {
|
||||
this.v = 0;
|
||||
// CraftBukkit start - Refresh list of who can see a player before sending teleport packet
|
||||
if (this.tracker instanceof EntityPlayer) {
|
||||
this.scanPlayers(new java.util.ArrayList(this.trackedPlayers));
|
||||
// SportPaper - Fix invisibility on teleport
|
||||
this.scanPlayers(new ArrayList<EntityHuman>(this.tracker.world.players));
|
||||
}
|
||||
// CraftBukkit end
|
||||
object = new PacketPlayOutEntityTeleport(this.tracker.getId(), i, j, k, (byte) l, (byte) i1, this.tracker.onGround);
|
||||
@ -272,7 +273,7 @@ public class EntityTrackerEntry {
|
||||
DataWatcher datawatcher = this.tracker.getDataWatcher();
|
||||
|
||||
if (datawatcher.a()) {
|
||||
if (eSpigotFeature.OBFUSCATE_HEALTH.isEnabled()) {
|
||||
if (eSpigotFeature.OBFUSCATE_HEALTH.isEnabled() && this.tracker instanceof EntityHuman) {
|
||||
List<DataWatcher.WatchableObject> changedMetadata = datawatcher.c();
|
||||
Iterator<DataWatcher.WatchableObject> iter = changedMetadata.iterator();
|
||||
boolean found = false;
|
||||
@ -423,13 +424,15 @@ public class EntityTrackerEntry {
|
||||
}
|
||||
|
||||
// CraftBukkit start - Fix for nonsensical head yaw
|
||||
if(this.tracker instanceof EntityLiving) { // SportPaper - avoid processing entities that can't change head rotation
|
||||
this.i = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F);
|
||||
// KigPaper
|
||||
if (this.tracker instanceof EntityLiving) {
|
||||
this.i = MathHelper.d(this.tracker.getHeadRotation() * 256.0F / 360.0F);
|
||||
// CraftBukkit what the fuck were you thinking?
|
||||
//this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i)); // KigPaper
|
||||
// SportPaper start
|
||||
// This was originally introduced by CraftBukkit, though the implementation is wrong since it's broadcasting
|
||||
// the packet again in a method that is already called for each player. This would create a very serious performance issue
|
||||
// with high player and entity counts (each sendPacket call involves waking up the event loop and flushing the network stream).
|
||||
// this.broadcast(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i));
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutEntityHeadRotation(this.tracker, (byte) i));
|
||||
// SportPaper end
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
|
@ -186,8 +186,12 @@ public class EntityWither extends EntityMonster implements IRangedEntity {
|
||||
|
||||
// CraftBukkit start - Use relative location for far away sounds
|
||||
// this.world.a(1013, new BlockPosition(this), 0);
|
||||
int viewDistance = this.world.getServer().getViewDistance() * 16;
|
||||
for (EntityPlayer player : MinecraftServer.getServer().getPlayerList().players) {
|
||||
// Paper start
|
||||
//int viewDistance = ((WorldServer) this.world).spigotConfig.viewDistance * 16; // Paper - updated to use worlds actual view distance incase we have to uncomment this due to removal of player view distance API
|
||||
for (EntityHuman human : world.players) {
|
||||
EntityPlayer player = (EntityPlayer) human;
|
||||
int viewDistance = player.viewDistance;
|
||||
// Paper end
|
||||
double deltaX = this.locX - player.locX;
|
||||
double deltaZ = this.locZ - player.locZ;
|
||||
double distanceSquared = deltaX * deltaX + deltaZ * deltaZ;
|
||||
|
@ -36,7 +36,8 @@ public class ItemBlock extends Item {
|
||||
this.a.postPlace(world, blockposition, iblockdata1, entityhuman, itemstack);
|
||||
}
|
||||
|
||||
world.makeSound((float) blockposition.getX() + 0.5F, (float) blockposition.getY() + 0.5F, (float) blockposition.getZ() + 0.5F, this.a.stepSound.getPlaceSound(), (this.a.stepSound.getVolume1() + 1.0F) / 2.0F, this.a.stepSound.getVolume2() * 0.8F);
|
||||
// SPIGOT-1288
|
||||
// world.makeSound((double) ((float) blockposition.getX() + 0.5F), (double) ((float) blockposition.getY() + 0.5F), (double) ((float) blockposition.getZ() + 0.5F), this.a.stepSound.getPlaceSound(), (this.a.stepSound.getVolume1() + 1.0F) / 2.0F, this.a.stepSound.getVolume2() * 0.8F);
|
||||
--itemstack.count;
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@ public class ItemBucket extends Item {
|
||||
PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent(entityhuman, blockposition.getX(), blockposition.getY(), blockposition.getZ(), null, itemstack, Items.WATER_BUCKET);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
((EntityPlayer)entityhuman).updateInventory(entityhuman.defaultContainer);
|
||||
return itemstack;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@ -59,6 +60,7 @@ public class ItemBucket extends Item {
|
||||
PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent(entityhuman, blockposition.getX(), blockposition.getY(), blockposition.getZ(), null, itemstack, Items.LAVA_BUCKET);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
((EntityPlayer)entityhuman).updateInventory(entityhuman.defaultContainer);
|
||||
return itemstack;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@ -72,6 +74,7 @@ public class ItemBucket extends Item {
|
||||
PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent(entityhuman, blockposition.getX(), blockposition.getY(), blockposition.getZ(), movingobjectposition.direction, itemstack);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
((EntityPlayer)entityhuman).updateInventory(entityhuman.defaultContainer);
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
@ -86,12 +89,13 @@ public class ItemBucket extends Item {
|
||||
}
|
||||
|
||||
// CraftBukkit start
|
||||
// Check that the bucket can be emptied before firing the event
|
||||
if (world.isEmpty(blockposition1) || !world.getType(blockposition1).getBlock().getMaterial().isBuildable()) {
|
||||
PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent(entityhuman, blockposition.getX(), blockposition.getY(), blockposition.getZ(), movingobjectposition.direction, itemstack);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
((EntityPlayer)entityhuman).updateInventory(entityhuman.defaultContainer);
|
||||
return itemstack;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
if (this.a(world, blockposition1) && !entityhuman.abilities.canInstantlyBuild) {
|
||||
entityhuman.b(StatisticList.USE_ITEM_COUNT[Item.getId(this)]);
|
||||
@ -106,6 +110,7 @@ public class ItemBucket extends Item {
|
||||
}
|
||||
return itemstack;
|
||||
}
|
||||
}
|
||||
// PaperSpigot end
|
||||
return CraftItemStack.asNMSCopy(event.getItemStack()); // CraftBukkit
|
||||
}
|
||||
|
@ -218,6 +218,12 @@ public final class ItemStack {
|
||||
}
|
||||
}
|
||||
|
||||
// SPIGOT-1288 - play sound stripped from ItemBlock
|
||||
if (this.getItem() instanceof ItemBlock) {
|
||||
Block base = ((ItemBlock) this.getItem()).a;
|
||||
world.makeSound((double) ((float) blockposition.getX() + 0.5F), (double) ((float) blockposition.getY() + 0.5F), (double) ((float) blockposition.getZ() + 0.5F), base.stepSound.getPlaceSound(), (base.stepSound.getVolume1() + 1.0F) / 2.0F, base.stepSound.getVolume2() * 0.8F);
|
||||
}
|
||||
|
||||
entityhuman.b(StatisticList.USE_ITEM_COUNT[Item.getId(this.item)]);
|
||||
}
|
||||
}
|
||||
|
@ -48,8 +48,18 @@ public class LoginListener implements PacketLoginInListener, IUpdatePlayerListBo
|
||||
}
|
||||
|
||||
public void c() {
|
||||
// Paper start - Do not allow logins while the server is shutting down
|
||||
if (!MinecraftServer.getServer().isRunning()) {
|
||||
this.disconnect(org.spigotmc.SpigotConfig.restartMessage);
|
||||
return;
|
||||
}
|
||||
// Paper end
|
||||
if (this.g == LoginListener.EnumProtocolState.READY_TO_ACCEPT) {
|
||||
// Paper start - prevent logins to be processed even though disconnect was called
|
||||
if (networkManager.channel != null && networkManager.channel.isOpen()) {
|
||||
this.b();
|
||||
}
|
||||
// Paper end
|
||||
} else if (this.g == LoginListener.EnumProtocolState.e) {
|
||||
EntityPlayer entityplayer = this.server.getPlayerList().a(this.i.getId());
|
||||
|
||||
@ -239,10 +249,41 @@ public class LoginListener implements PacketLoginInListener, IUpdatePlayerListBo
|
||||
}
|
||||
}
|
||||
|
||||
// Paper start - Delay async prelogin until plugins are ready
|
||||
private static volatile Object blockingLogins = new Object();
|
||||
|
||||
public static void checkStartupAndBlock() {
|
||||
final Object lock = LoginListener.blockingLogins;
|
||||
if (lock != null) {
|
||||
synchronized (lock) {
|
||||
for (;;) {
|
||||
if (LoginListener.blockingLogins == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (final InterruptedException ignore) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void allowLogins() {
|
||||
final Object lock = LoginListener.blockingLogins;
|
||||
synchronized (lock) {
|
||||
LoginListener.blockingLogins = null;
|
||||
lock.notifyAll();
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
// Spigot start
|
||||
public class LoginHandler {
|
||||
|
||||
public void fireEvents() throws Exception {
|
||||
LoginListener.checkStartupAndBlock(); // Paper - Delay async login events until plugins are ready
|
||||
String playerName = i.getName();
|
||||
java.net.InetAddress address = ((java.net.InetSocketAddress) networkManager.getSocketAddress()).getAddress();
|
||||
java.util.UUID uniqueId = i.getId();
|
||||
@ -263,7 +304,7 @@ public class LoginListener implements PacketLoginInListener, IUpdatePlayerListBo
|
||||
return event.getResult();
|
||||
}};
|
||||
|
||||
LoginListener.this.server.processQueue.add(waitable);
|
||||
LoginListener.this.server.addMainThreadTask(waitable);
|
||||
if (waitable.get() != PlayerPreLoginEvent.Result.ALLOWED) {
|
||||
disconnect(event.getKickMessage());
|
||||
return;
|
||||
|
142
TacoSpigot-Server/src/main/java/net/minecraft/server/MCUtil.java
Normal file
142
TacoSpigot-Server/src/main/java/net/minecraft/server/MCUtil.java
Normal file
@ -0,0 +1,142 @@
|
||||
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.craftbukkit.util.Waitable;
|
||||
import org.spigotmc.AsyncCatcher;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class MCUtil {
|
||||
private static final Executor asyncExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("Paper Async Task Handler Thread - %1$d").build());
|
||||
|
||||
private MCUtil() {}
|
||||
|
||||
/**
|
||||
* Quickly generate a stack trace for current location
|
||||
*
|
||||
* @return Stacktrace
|
||||
*/
|
||||
public static String stack() {
|
||||
return ExceptionUtils.getFullStackTrace(new Throwable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly generate a stack trace for current location with message
|
||||
*
|
||||
* @param str
|
||||
* @return Stacktrace
|
||||
*/
|
||||
public static String stack(String str) {
|
||||
return ExceptionUtils.getFullStackTrace(new Throwable(str));
|
||||
}
|
||||
|
||||
public static <T> T ensureMain(String reason, Supplier<T> run) {
|
||||
if (AsyncCatcher.enabled && Thread.currentThread() != MinecraftServer.getServer().primaryThread) {
|
||||
new IllegalStateException( "Asynchronous " + reason + "! Blocking thread until it returns ").printStackTrace();
|
||||
Waitable<T> wait = new Waitable<T>() {
|
||||
@Override
|
||||
protected T evaluate() {
|
||||
return run.get();
|
||||
}
|
||||
};
|
||||
MinecraftServer.getServer().addMainThreadTask(wait);
|
||||
try {
|
||||
return wait.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return run.get();
|
||||
}
|
||||
|
||||
public static double distance(Entity e1, Entity e2) {
|
||||
return Math.sqrt(distanceSq(e1, e2));
|
||||
}
|
||||
|
||||
public static double distance(BlockPosition e1, BlockPosition e2) {
|
||||
return Math.sqrt(distanceSq(e1, e2));
|
||||
}
|
||||
|
||||
public static double distance(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
return Math.sqrt(distanceSq(x1, y1, z1, x2, y2, z2));
|
||||
}
|
||||
|
||||
public static double distanceSq(Entity e1, Entity e2) {
|
||||
return distanceSq(e1.locX,e1.locY,e1.locZ, e2.locX,e2.locY,e2.locZ);
|
||||
}
|
||||
|
||||
public static double distanceSq(BlockPosition pos1, BlockPosition pos2) {
|
||||
return distanceSq(pos1.getX(), pos1.getY(), pos1.getZ(), pos2.getX(), pos2.getY(), pos2.getZ());
|
||||
}
|
||||
|
||||
public static double distanceSq(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2);
|
||||
}
|
||||
|
||||
public static Location toLocation(World world, double x, double y, double z) {
|
||||
return new Location(world.getWorld(), x, y, z);
|
||||
}
|
||||
|
||||
public static Location toLocation(World world, BlockPosition pos) {
|
||||
return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
public static Location toLocation(Entity entity) {
|
||||
return new Location(entity.getWorld().getWorld(), entity.locX, entity.locY, entity.locZ);
|
||||
}
|
||||
|
||||
public static BlockPosition toBlockPosition(Location loc) {
|
||||
return new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
}
|
||||
|
||||
public static boolean isEdgeOfChunk(BlockPosition pos) {
|
||||
final int modX = pos.getX() & 15;
|
||||
final int modZ = pos.getZ() & 15;
|
||||
return (modX == 0 || modX == 15 || modZ == 0 || modZ == 15);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Chunk getLoadedChunkWithoutMarkingActive(World world, int x, int z) {
|
||||
return ((ChunkProviderServer) world.chunkProvider).chunks.get(ChunkCoordIntPair.a(x, z));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Chunk getLoadedChunkWithoutMarkingActive(IChunkProvider provider, int x, int z) {
|
||||
return ((ChunkProviderServer)provider).chunks.get(ChunkCoordIntPair.a(x, z));
|
||||
}
|
||||
|
||||
public static void scheduleAsyncTask(Runnable run) {
|
||||
asyncExecutor.execute(run);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static TileEntityHopper getHopper(World world, BlockPosition pos) {
|
||||
Chunk chunk = world.getChunkIfLoaded(pos.getX() >> 4, pos.getZ() >> 4);
|
||||
if (chunk != null && chunk.getBlockData(pos).getBlock() == Blocks.HOPPER) {
|
||||
TileEntity tileEntity = chunk.getTileEntityImmediately(pos);
|
||||
if (tileEntity instanceof TileEntityHopper) {
|
||||
return (TileEntityHopper) tileEntity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static World getNMSWorld(@Nonnull org.bukkit.World world) {
|
||||
return ((CraftWorld) world).getHandle();
|
||||
}
|
||||
|
||||
public static World getNMSWorld(@Nonnull org.bukkit.entity.Entity entity) {
|
||||
return getNMSWorld(entity.getWorld());
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MerchantRecipeList extends ArrayList<MerchantRecipe> {
|
||||
|
||||
public MerchantRecipeList() {}
|
||||
|
||||
public MerchantRecipeList(NBTTagCompound nbttagcompound) {
|
||||
this.a(nbttagcompound);
|
||||
}
|
||||
|
||||
public MerchantRecipe a(ItemStack itemstack, ItemStack itemstack1, int i) {
|
||||
if (i > 0 && i < this.size()) {
|
||||
MerchantRecipe merchantrecipe = this.get(i);
|
||||
|
||||
return this.a(itemstack, merchantrecipe.getBuyItem1()) && (itemstack1 == null && !merchantrecipe.hasSecondItem() || merchantrecipe.hasSecondItem() && this.a(itemstack1, merchantrecipe.getBuyItem2())) && itemstack.count >= merchantrecipe.getBuyItem1().count && (!merchantrecipe.hasSecondItem() || itemstack1.count >= merchantrecipe.getBuyItem2().count) ? merchantrecipe : null;
|
||||
} else {
|
||||
for (int j = 0; j < this.size(); ++j) {
|
||||
MerchantRecipe merchantrecipe1 = this.get(j);
|
||||
|
||||
if (this.a(itemstack, merchantrecipe1.getBuyItem1()) && itemstack.count >= merchantrecipe1.getBuyItem1().count && (!merchantrecipe1.hasSecondItem() && itemstack1 == null || merchantrecipe1.hasSecondItem() && this.a(itemstack1, merchantrecipe1.getBuyItem2()) && itemstack1.count >= merchantrecipe1.getBuyItem2().count)) {
|
||||
return merchantrecipe1;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean a(ItemStack itemstack, ItemStack itemstack1) {
|
||||
return ItemStack.c(itemstack, itemstack1) && (!itemstack1.hasTag() || itemstack.hasTag() && GameProfileSerializer.a(itemstack1.getTag(), itemstack.getTag(), false));
|
||||
}
|
||||
|
||||
public void a(PacketDataSerializer packetdataserializer) {
|
||||
packetdataserializer.writeByte((byte) (this.size() & 255));
|
||||
|
||||
for (int i = 0; i < this.size(); ++i) {
|
||||
MerchantRecipe merchantrecipe = this.get(i);
|
||||
|
||||
packetdataserializer.a(merchantrecipe.getBuyItem1());
|
||||
packetdataserializer.a(merchantrecipe.getBuyItem3());
|
||||
ItemStack itemstack = merchantrecipe.getBuyItem2();
|
||||
|
||||
packetdataserializer.writeBoolean(itemstack != null);
|
||||
if (itemstack != null) {
|
||||
packetdataserializer.a(itemstack);
|
||||
}
|
||||
|
||||
packetdataserializer.writeBoolean(merchantrecipe.h());
|
||||
packetdataserializer.writeInt(merchantrecipe.e());
|
||||
packetdataserializer.writeInt(merchantrecipe.f());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void a(NBTTagCompound nbttagcompound) {
|
||||
NBTTagList nbttaglist = nbttagcompound.getList("Recipes", 10);
|
||||
|
||||
for (int i = 0; i < nbttaglist.size(); ++i) {
|
||||
NBTTagCompound nbttagcompound1 = nbttaglist.get(i);
|
||||
|
||||
this.add(new MerchantRecipe(nbttagcompound1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public NBTTagCompound a() {
|
||||
NBTTagCompound nbttagcompound = new NBTTagCompound();
|
||||
NBTTagList nbttaglist = new NBTTagList();
|
||||
|
||||
for (int i = 0; i < this.size(); ++i) {
|
||||
MerchantRecipe merchantrecipe = (MerchantRecipe) this.get(i);
|
||||
if (merchantrecipe.getBuyItem1() == null) continue;
|
||||
nbttaglist.add(merchantrecipe.k());
|
||||
}
|
||||
|
||||
nbttagcompound.set("Recipes", nbttaglist);
|
||||
return nbttagcompound;
|
||||
}
|
||||
}
|
@ -37,6 +37,7 @@ import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
// CraftBukkit end
|
||||
@ -64,8 +65,8 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
|
||||
public final RollingAverage tps15 = new RollingAverage(60 * 15);
|
||||
protected final ICommandHandler b;
|
||||
protected final Proxy e;
|
||||
protected final Queue<FutureTask<?>> j = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Spigot, PAIL: Rename
|
||||
protected final Queue<FutureTask<?>> fastPackets = new java.util.concurrent.ConcurrentLinkedQueue<>(); // eSpigot
|
||||
protected final Deque<FutureTask<?>> j = new ConcurrentLinkedDeque<>(); // Spigot, PAIL: Rename // Paper - Make size() constant-time
|
||||
public final Deque<FutureTask<?>> taskQueue = j; // SportBukkit - alias and downcast
|
||||
private final MojangStatisticsGenerator n = new MojangStatisticsGenerator("server", this, az());
|
||||
private final List<IUpdatePlayerListBox> p = Lists.newArrayList();
|
||||
private final ServerPing r = new ServerPing();
|
||||
@ -89,7 +90,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
|
||||
public org.bukkit.command.ConsoleCommandSender console;
|
||||
public org.bukkit.command.RemoteConsoleCommandSender remoteConsole;
|
||||
public ConsoleReader reader;
|
||||
public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<>();
|
||||
//public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>(); SportBukkit - use Mojang's task queue
|
||||
public int autosavePeriod;
|
||||
public double[] recentTps = new double[3]; // PaperSpigot - Fine have your darn compat with bad plugins
|
||||
|
||||
@ -600,6 +601,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
|
||||
this.g = 0;
|
||||
|
||||
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD); // CraftBukkit
|
||||
LoginListener.allowLogins(); // Paper - Allow logins once postworld
|
||||
}
|
||||
|
||||
protected void saveChunks(boolean flag) throws ExceptionWorldConflict { // CraftBukkit - added throws
|
||||
@ -677,7 +679,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
|
||||
// Spigot start
|
||||
if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) {
|
||||
LOGGER.info("Saving usercache.json");
|
||||
this.Z.c();
|
||||
this.Z.c(false); // Paper
|
||||
}
|
||||
//Spigot end
|
||||
|
||||
@ -939,15 +941,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
|
||||
public void B() {
|
||||
SpigotTimings.minecraftSchedulerTimer.startTiming(); // Spigot
|
||||
this.methodProfiler.a("jobs");
|
||||
Queue queue = this.j;
|
||||
|
||||
// Spigot start
|
||||
FutureTask<?> entry;
|
||||
int count = this.j.size();
|
||||
while (count-- > 0 && (entry = this.j.poll()) != null) {
|
||||
SystemUtils.a(entry, MinecraftServer.LOGGER);
|
||||
}
|
||||
// Spigot end
|
||||
processTasks();
|
||||
SpigotTimings.minecraftSchedulerTimer.stopTiming(); // Spigot
|
||||
|
||||
this.methodProfiler.c("levels");
|
||||
@ -957,13 +951,6 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
|
||||
this.server.getScheduler().mainThreadHeartbeat(this.ticks);
|
||||
SpigotTimings.bukkitSchedulerTimer.stopTiming(); // Spigot
|
||||
|
||||
// Run tasks that are waiting on processing
|
||||
SpigotTimings.processQueueTimer.startTiming(); // Spigot
|
||||
while (!processQueue.isEmpty()) {
|
||||
processQueue.remove().run();
|
||||
}
|
||||
SpigotTimings.processQueueTimer.stopTiming(); // Spigot
|
||||
|
||||
SpigotTimings.chunkIOTickTimer.startTiming(); // Spigot
|
||||
org.bukkit.craftbukkit.chunkio.ChunkIOExecutor.tick();
|
||||
SpigotTimings.chunkIOTickTimer.stopTiming(); // Spigot
|
||||
@ -988,6 +975,7 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
|
||||
|
||||
// if (i == 0 || this.getAllowNether()) {
|
||||
WorldServer worldserver = this.worlds.get(i);
|
||||
if(!worldserver.getWorld().checkTicking()) continue; // SportBukkit
|
||||
|
||||
this.methodProfiler.a(worldserver.getWorldData().getName());
|
||||
/* Drop global time updates
|
||||
@ -1654,6 +1642,48 @@ public abstract class MinecraftServer implements Runnable, ICommandListener, IAs
|
||||
return Thread.currentThread() == this.serverThread;
|
||||
}
|
||||
|
||||
// SportBukkit start
|
||||
public void addMainThreadTask(FutureTask<?> task) {
|
||||
addMainThreadTask(false, task);
|
||||
}
|
||||
|
||||
public void addMainThreadTask(boolean priority, FutureTask<?> task) {
|
||||
synchronized(taskQueue) {
|
||||
if(priority) {
|
||||
//taskQueue.
|
||||
taskQueue.addFirst(task);
|
||||
} else {
|
||||
taskQueue.addLast(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addMainThreadTask(Runnable task) {
|
||||
addMainThreadTask(false, task);
|
||||
}
|
||||
|
||||
public <T> ListenableFuture<T> addMainThreadTask(boolean priority, Runnable task) {
|
||||
final ListenableFutureTask<T> future = ListenableFutureTask.create(task, null);
|
||||
addMainThreadTask(priority, future);
|
||||
return future;
|
||||
}
|
||||
|
||||
protected void processTasks() {
|
||||
if(!isMainThread()) throw new IllegalStateException("Tasks must be processed on the main thread");
|
||||
for(;;) {
|
||||
final FutureTask<?> task;
|
||||
synchronized(taskQueue) {
|
||||
task = taskQueue.poll();
|
||||
}
|
||||
if(task == null) {
|
||||
break;
|
||||
} else {
|
||||
SystemUtils.a(task, MinecraftServer.LOGGER);
|
||||
}
|
||||
}
|
||||
}
|
||||
// SportBukkit end
|
||||
|
||||
public int aK() {
|
||||
return 256;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import org.apache.logging.log4j.Logger;
|
||||
public class NBTTagList extends NBTBase {
|
||||
|
||||
private static final Logger b = LogManager.getLogger();
|
||||
private List<NBTBase> list = Lists.newArrayList();
|
||||
public List<NBTBase> list = Lists.newArrayList(); // Paper
|
||||
private byte type = 0;
|
||||
|
||||
public NBTTagList() {}
|
||||
|
@ -5,7 +5,7 @@ import java.util.List;
|
||||
|
||||
public abstract class NavigationAbstract {
|
||||
|
||||
protected EntityInsentient b;
|
||||
protected EntityInsentient b; public Entity getEntity() { return b; } // Paper - OBFHELPER
|
||||
protected World c;
|
||||
protected PathEntity d;
|
||||
protected double e;
|
||||
@ -38,6 +38,7 @@ public abstract class NavigationAbstract {
|
||||
}
|
||||
|
||||
public PathEntity a(BlockPosition blockposition) {
|
||||
if (!getEntity().getWorld().getWorldBorder().isInBounds(blockposition)) return null; // Paper - don't path out of world border
|
||||
if (!this.b()) {
|
||||
return null;
|
||||
} else {
|
||||
@ -72,6 +73,7 @@ public abstract class NavigationAbstract {
|
||||
|
||||
this.c.methodProfiler.a("pathfind");
|
||||
BlockPosition blockposition = (new BlockPosition(this.b)).up();
|
||||
if (!getEntity().getWorld().getWorldBorder().isInBounds(blockposition)) return null; // Paper - don't path out of world border
|
||||
int i = (int) (f + 16.0F);
|
||||
ChunkCache chunkcache = new ChunkCache(this.c, blockposition.a(-i, -i, -i), blockposition.a(i, i, i), 0);
|
||||
PathEntity pathentity = this.j.a(chunkcache, this.b, entity, f);
|
||||
|
@ -81,33 +81,18 @@ public class PacketPlayOutSpawnEntity implements Packet<PacketListenerPlayOut> {
|
||||
this.d = packetdataserializer.readInt();
|
||||
this.h = packetdataserializer.readByte();
|
||||
this.i = packetdataserializer.readByte();
|
||||
this.k = packetdataserializer.readInt();
|
||||
if (this.k > 0) {
|
||||
this.e = packetdataserializer.readShort();
|
||||
this.f = packetdataserializer.readShort();
|
||||
this.g = packetdataserializer.readShort();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void b(PacketDataSerializer packetdataserializer) throws IOException {
|
||||
packetdataserializer.b(this.a);
|
||||
packetdataserializer.writeByte(this.j);
|
||||
switch (this.k) {
|
||||
case 0: {
|
||||
this.d -= 32;
|
||||
this.i = 128;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
this.b += 32;
|
||||
this.i = 64;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
this.d += 32;
|
||||
this.i = 0;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
this.b -= 32;
|
||||
this.i = 192;
|
||||
break;
|
||||
}
|
||||
}
|
||||
packetdataserializer.writeInt(this.b);
|
||||
packetdataserializer.writeInt(this.c);
|
||||
packetdataserializer.writeInt(this.d);
|
||||
@ -119,6 +104,7 @@ public class PacketPlayOutSpawnEntity implements Packet<PacketListenerPlayOut> {
|
||||
packetdataserializer.writeShort(this.f);
|
||||
packetdataserializer.writeShort(this.g);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void b_old(PacketDataSerializer packetdataserializer) throws IOException {
|
||||
|
@ -23,6 +23,7 @@ import org.apache.logging.log4j.Logger;
|
||||
|
||||
// CraftBukkit start
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
|
||||
import java.util.HashSet;
|
||||
|
||||
@ -79,11 +80,12 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
private int g;
|
||||
private boolean h;
|
||||
private int i;
|
||||
private long j;
|
||||
private long k;
|
||||
private long j; private void setLastPing(long lastPing) { this.j = lastPing;}; private long getLastPing() { return this.j;}; // Paper - OBFHELPER
|
||||
private long k; private void setKeepAliveID(long keepAliveID) { this.k = keepAliveID;}; private long getKeepAliveID() {return this.k; }; // Paper - OBFHELPER
|
||||
// CraftBukkit start - multithreaded fields
|
||||
private volatile int chatThrottle;
|
||||
private static final AtomicIntegerFieldUpdater chatSpamField = AtomicIntegerFieldUpdater.newUpdater(PlayerConnection.class, "chatThrottle");
|
||||
private final AtomicInteger tabSpamLimiter = new java.util.concurrent.atomic.AtomicInteger(); // Paper - configurable tab spam limits
|
||||
// CraftBukkit end
|
||||
private int m;
|
||||
private IntHashMap<Short> n = new IntHashMap();
|
||||
@ -142,6 +144,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
this.minecraftServer.methodProfiler.b();
|
||||
// CraftBukkit start
|
||||
for (int spam; (spam = this.chatThrottle) > 0 && !chatSpamField.compareAndSet(this, spam, spam - 1); ) ;
|
||||
if (tabSpamLimiter.get() > 0) tabSpamLimiter.getAndDecrement(); // Paper - split to seperate variable
|
||||
/* Use thread-safe field access instead
|
||||
if (this.chatThrottle > 0) {
|
||||
--this.chatThrottle;
|
||||
@ -648,6 +651,8 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
double d3 = d0 * d0 + d1 * d1 + d2 * d2;
|
||||
|
||||
if (d3 > 36.0D) {
|
||||
if (worldserver.isChunkLoaded(blockposition.getX() >> 4, blockposition.getZ() >> 4, true)) // Paper - Fix block break desync - Don't send for unloaded chunks
|
||||
this.sendPacket(new PacketPlayOutBlockChange(worldserver, blockposition)); // Paper - Fix block break desync
|
||||
return;
|
||||
} else if (blockposition.getY() >= this.minecraftServer.getMaxBuildHeight()) {
|
||||
return;
|
||||
@ -761,7 +766,24 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
}
|
||||
}
|
||||
|
||||
if (!cancelled) {
|
||||
if (cancelled) {
|
||||
this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524
|
||||
// SportPaper start - Fix client desync
|
||||
if (itemstack.getItem() == Item.getItemOf(Blocks.WATERLILY)) {
|
||||
MovingObjectPosition movingObjectPosition1 = this.player.world.rayTrace(vec3d, vec3d1, true, false, false);
|
||||
if (movingObjectPosition1 != null) {
|
||||
BlockPosition blockPosition = movingObjectPosition1.a().up();
|
||||
org.bukkit.craftbukkit.block.CraftBlockState.getBlockState(worldserver, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()).update(true, false);
|
||||
}
|
||||
} else if (itemstack.getItem() == Items.BUCKET) {
|
||||
MovingObjectPosition movingObjectPosition1 = this.player.world.rayTrace(vec3d, vec3d1, true, false, false);
|
||||
if (movingObjectPosition1 != null) {
|
||||
BlockPosition blockPosition = movingObjectPosition1.a();
|
||||
org.bukkit.craftbukkit.block.CraftBlockState.getBlockState(worldserver, blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()).update(true, false);
|
||||
}
|
||||
}
|
||||
// SportPaper end
|
||||
} else {
|
||||
this.player.playerInteractManager.useItem(this.player, this.player.world, itemstack);
|
||||
}
|
||||
}
|
||||
@ -1019,7 +1041,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
}
|
||||
};
|
||||
|
||||
this.minecraftServer.processQueue.add(waitable);
|
||||
this.minecraftServer.addMainThreadTask(waitable);
|
||||
|
||||
try {
|
||||
waitable.get();
|
||||
@ -1049,7 +1071,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
} else if (getPlayer().isConversing()) {
|
||||
// Spigot start
|
||||
final String message = s;
|
||||
this.minecraftServer.processQueue.add( new Waitable()
|
||||
this.minecraftServer.addMainThreadTask( new Waitable()
|
||||
{
|
||||
@Override
|
||||
protected Object evaluate()
|
||||
@ -1096,7 +1118,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
}
|
||||
};
|
||||
|
||||
this.minecraftServer.processQueue.add(waitable);
|
||||
this.minecraftServer.addMainThreadTask(waitable);
|
||||
|
||||
try {
|
||||
waitable.get();
|
||||
@ -1133,7 +1155,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
return null;
|
||||
}
|
||||
};
|
||||
minecraftServer.processQueue.add(wait);
|
||||
minecraftServer.addMainThreadTask(wait);
|
||||
try {
|
||||
wait.get();
|
||||
return;
|
||||
@ -1179,7 +1201,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
return null;
|
||||
}};
|
||||
if (async) {
|
||||
minecraftServer.processQueue.add(waitable);
|
||||
minecraftServer.addMainThreadTask(waitable);
|
||||
} else {
|
||||
waitable.run();
|
||||
}
|
||||
@ -1435,6 +1457,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
}
|
||||
|
||||
if (event.isCancelled()) {
|
||||
this.player.updateInventory(this.player.activeContainer); // Paper - Refresh player inventory
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@ -1565,7 +1588,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
}
|
||||
if (packetplayinwindowclick.c() == 0 || packetplayinwindowclick.c() == 1) {
|
||||
action = InventoryAction.NOTHING; // Don't want to repeat ourselves
|
||||
if (packetplayinwindowclick.b() == -999) {
|
||||
if (packetplayinwindowclick.b() < 0) { // Paper - GH-404
|
||||
if (player.inventory.getCarried() != null) {
|
||||
action = packetplayinwindowclick.c() == 0 ? InventoryAction.DROP_ALL_CURSOR : InventoryAction.DROP_ONE_CURSOR;
|
||||
}
|
||||
@ -2006,6 +2029,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
|
||||
}
|
||||
|
||||
private long getCurrentMillis() { return d(); } // Paper - OBFHELPER
|
||||
private long d() {
|
||||
return System.nanoTime() / 1000000L;
|
||||
}
|
||||
@ -2028,7 +2052,7 @@ public class PlayerConnection implements PacketListenerPlayIn, IUpdatePlayerList
|
||||
public void a(PacketPlayInTabComplete packetplayintabcomplete) {
|
||||
PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.u());
|
||||
// CraftBukkit start
|
||||
if (chatSpamField.addAndGet(this, 10) > 500 && !this.minecraftServer.getPlayerList().isOp(this.player.getProfile())) {
|
||||
if (tabSpamLimiter.addAndGet(PaperSpigotConfig.tabSpamIncrement) > PaperSpigotConfig.tabSpamLimit && !this.minecraftServer.getPlayerList().isOp(this.player.getProfile())) { // Paper start - split and make configurable
|
||||
this.disconnect("disconnect.spam");
|
||||
return;
|
||||
}
|
||||
|
@ -157,6 +157,7 @@ public abstract class PlayerList {
|
||||
playerconnection.sendPacket(new PacketPlayOutSpawnPosition(blockposition));
|
||||
playerconnection.sendPacket(new PacketPlayOutAbilities(entityplayer.abilities));
|
||||
playerconnection.sendPacket(new PacketPlayOutHeldItemSlot(entityplayer.inventory.itemInHandIndex));
|
||||
playerconnection.sendPacket(new PacketPlayOutEntityStatus(entityplayer, (byte) (worldserver.getGameRules().getBoolean("reducedDebugInfo") ? 22 : 23))); // Paper - fix this rule not being initialized on the client
|
||||
entityplayer.getStatisticManager().d();
|
||||
entityplayer.getStatisticManager().updateStatistics(entityplayer);
|
||||
this.sendScoreboard((ScoreboardServer) worldserver.getScoreboard(), entityplayer);
|
||||
@ -561,6 +562,7 @@ public abstract class PlayerList {
|
||||
BlockPosition blockposition1;
|
||||
|
||||
// CraftBukkit start - fire PlayerRespawnEvent
|
||||
this.players.add(entityplayer); // Add player back to this list earlier than vanilla does
|
||||
if (location == null) {
|
||||
boolean isBedSpawn = false;
|
||||
CraftWorld cworld = (CraftWorld) this.server.server.getWorld(entityplayer.spawnWorld);
|
||||
@ -622,10 +624,12 @@ public abstract class PlayerList {
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutExperience(entityplayer.exp, entityplayer.expTotal, entityplayer.expLevel));
|
||||
this.b(entityplayer, worldserver);
|
||||
|
||||
if (!entityplayer.playerConnection.isDisconnected()) {
|
||||
// Don't re-add player to player list if disconnected
|
||||
if (entityplayer.playerConnection.isDisconnected()) {
|
||||
this.players.remove(entityplayer);
|
||||
} else {
|
||||
worldserver.getPlayerChunkMap().addPlayer(entityplayer);
|
||||
worldserver.addEntity(entityplayer);
|
||||
this.players.add(entityplayer);
|
||||
this.playersByName.put(entityplayer.getName(), entityplayer); // Spigot
|
||||
this.j.put(entityplayer.getUniqueID(), entityplayer);
|
||||
}
|
||||
|
@ -1,16 +1,19 @@
|
||||
package net.minecraft.server;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.github.paperspigot.PaperSpigotConfig;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RegionFileCache {
|
||||
|
||||
public static final Map<File, RegionFile> a = Maps.newHashMap(); // Spigot - private -> public
|
||||
public static final Map<File, RegionFile> a = new LinkedHashMap(PaperSpigotConfig.regionFileCacheSize, 0.75f, true); // Spigot - private -> public, Paper - HashMap -> LinkedHashMap
|
||||
|
||||
// PaperSpigot start
|
||||
public static synchronized RegionFile a(File file, int i, int j) {
|
||||
@ -30,8 +33,8 @@ public class RegionFileCache {
|
||||
file1.mkdirs();
|
||||
}
|
||||
|
||||
if (RegionFileCache.a.size() >= 256) {
|
||||
a();
|
||||
if (RegionFileCache.a.size() >= PaperSpigotConfig.regionFileCacheSize) { // Paper
|
||||
trimCache(); // Paper
|
||||
}
|
||||
|
||||
RegionFile regionfile1 = new RegionFile(file2);
|
||||
@ -41,6 +44,21 @@ public class RegionFileCache {
|
||||
}
|
||||
}
|
||||
|
||||
// Paper Start
|
||||
private static synchronized void trimCache() {
|
||||
Iterator<Map.Entry<File, RegionFile>> itr = RegionFileCache.a.entrySet().iterator();
|
||||
int count = RegionFileCache.a.size() - PaperSpigotConfig.regionFileCacheSize;
|
||||
while (count-- >= 0 && itr.hasNext()) {
|
||||
try {
|
||||
itr.next().getValue().c();
|
||||
} catch (IOException ioexception) {
|
||||
ioexception.printStackTrace();
|
||||
}
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
// Paper End
|
||||
|
||||
public static synchronized void a() {
|
||||
|
||||
for (RegionFile regionfile : RegionFileCache.a.values()) {
|
||||
|
@ -21,6 +21,7 @@ import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@ -69,7 +70,7 @@ public class ServerConnection {
|
||||
this.d = true;
|
||||
}
|
||||
|
||||
// KigPaper start - Paper-0117 by Aikar
|
||||
// Paper start - prevent blocking on adding a new network manager while the server is ticking
|
||||
private final List<NetworkManager> pending = Collections.synchronizedList(Lists.newArrayList());
|
||||
private void addPending() {
|
||||
synchronized (pending) {
|
||||
@ -77,7 +78,7 @@ public class ServerConnection {
|
||||
pending.clear();
|
||||
}
|
||||
}
|
||||
// KigPaper end
|
||||
// Paper end
|
||||
|
||||
public void a(InetAddress inetaddress, int i) throws IOException {
|
||||
List list = this.g;
|
||||
@ -115,7 +116,7 @@ public class ServerConnection {
|
||||
NetworkManager networkmanager = new NetworkManager(EnumProtocolDirection.SERVERBOUND);
|
||||
|
||||
//ServerConnection.this.h.add(networkmanager);
|
||||
pending.add(networkmanager); // KigPaper
|
||||
pending.add(networkmanager); // Paper
|
||||
channel.pipeline().addLast("packet_handler", networkmanager);
|
||||
networkmanager.a(new HandshakeListener(ServerConnection.this.f, networkmanager));
|
||||
}
|
||||
@ -126,14 +127,26 @@ public class ServerConnection {
|
||||
public void b() {
|
||||
this.d = false;
|
||||
|
||||
// CraftBukkit start - handle processQueue while closing channels to prevent deadlock
|
||||
ArrayList<ChannelFuture> futures = new ArrayList<ChannelFuture>();
|
||||
|
||||
for (ChannelFuture channelfuture : this.g) {
|
||||
try {
|
||||
channelfuture.channel().close().sync();
|
||||
} catch (InterruptedException interruptedexception) {
|
||||
ServerConnection.e.error("Interrupted whilst closing channel");
|
||||
}
|
||||
futures.add(channelfuture.channel().close());
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
futures.removeIf(java.util.concurrent.Future::isDone);
|
||||
f.processTasks();
|
||||
|
||||
if(futures.isEmpty()) break;
|
||||
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch(InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
public void processFastPackets() {
|
||||
|
@ -46,6 +46,7 @@ public final class SpawnerCreature {
|
||||
// Spigot end
|
||||
|
||||
public int a(WorldServer worldserver, boolean flag, boolean flag1, boolean flag2) {
|
||||
org.spigotmc.AsyncCatcher.catchOp("check for eligible spawn chunks"); // Paper - At least until we figure out what is calling this async
|
||||
if (!flag && !flag1) {
|
||||
return 0;
|
||||
} else {
|
||||
@ -122,8 +123,10 @@ public final class SpawnerCreature {
|
||||
// CraftBukkit end
|
||||
|
||||
if ((!enumcreaturetype.d() || flag1) && (enumcreaturetype.d() || flag) && (!enumcreaturetype.e() || flag2)) {
|
||||
/* Paper start - As far as I can tell neither of these are even used
|
||||
k = worldserver.a(enumcreaturetype.a());
|
||||
int l1 = limit * i / a; // CraftBukkit - use per-world limits
|
||||
*/ // Paper end
|
||||
|
||||
if ((mobcnt = getEntityCount(worldserver, enumcreaturetype.a())) <= limit * i / 289) { // TacoSpigot - use 17x17 like vanilla (a at top of file)
|
||||
Iterator iterator1 = this.b.iterator();
|
||||
|
@ -188,7 +188,7 @@ public class TileEntityFurnace extends TileEntityContainer implements IUpdatePla
|
||||
if (this.isBurning() && this.canBurn()) {
|
||||
this.cookTime += elapsedTicks;
|
||||
if (this.cookTime >= this.cookTimeTotal) {
|
||||
this.cookTime = 0;
|
||||
this.cookTime -= this.cookTimeTotal; // Paper
|
||||
this.cookTimeTotal = this.a(this.items[0]);
|
||||
this.burn();
|
||||
flag1 = true;
|
||||
|
@ -164,7 +164,7 @@ public class TileEntitySkull extends TileEntity {
|
||||
} else {
|
||||
executor.execute(() -> {
|
||||
final GameProfile profile1 = skinCache.getUnchecked(gameprofile.getName().toLowerCase());
|
||||
MinecraftServer.getServer().processQueue.add(() -> {
|
||||
MinecraftServer.getServer().addMainThreadTask(() -> {
|
||||
if (profile1 == null) {
|
||||
callback.apply(gameprofile);
|
||||
} else {
|
||||
|
@ -35,6 +35,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class UserCache {
|
||||
|
||||
@ -82,7 +83,7 @@ public class UserCache {
|
||||
};
|
||||
|
||||
minecraftserver.getGameProfileRepository().findProfilesByNames(new String[] { s}, Agent.MINECRAFT, profilelookupcallback);
|
||||
if (!minecraftserver.getOnlineMode() && agameprofile[0] == null) {
|
||||
if (!minecraftserver.getOnlineMode() && agameprofile[0] == null && !StringUtils.isBlank(s)) { // Paper - Don't lookup a profile with a blank
|
||||
UUID uuid = EntityHuman.a(new GameProfile(null, s));
|
||||
GameProfile gameprofile = new GameProfile(uuid, s);
|
||||
|
||||
@ -96,7 +97,7 @@ public class UserCache {
|
||||
this.a(gameprofile, null);
|
||||
}
|
||||
|
||||
private void a(GameProfile gameprofile, Date date) {
|
||||
private synchronized void a(GameProfile gameprofile, Date date) { // Paper - synchronize
|
||||
UUID uuid = gameprofile.getId();
|
||||
|
||||
if (date == null) {
|
||||
@ -110,8 +111,9 @@ public class UserCache {
|
||||
String s = gameprofile.getName().toLowerCase(Locale.ROOT);
|
||||
UserCache.UserCacheEntry usercache_usercacheentry = new UserCache.UserCacheEntry(gameprofile, date, null);
|
||||
|
||||
if (this.d.containsKey(uuid)) {
|
||||
//if (this.d.containsKey(uuid)) { // Paper
|
||||
UserCache.UserCacheEntry usercache_usercacheentry1 = this.d.get(uuid);
|
||||
if (usercache_usercacheentry1 != null) { // Paper
|
||||
|
||||
this.c.remove(usercache_usercacheentry1.a().getName().toLowerCase(Locale.ROOT));
|
||||
this.e.remove(gameprofile);
|
||||
@ -123,7 +125,7 @@ public class UserCache {
|
||||
if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.c(); // Spigot - skip saving if disabled
|
||||
}
|
||||
|
||||
public GameProfile getProfile(String s) {
|
||||
public synchronized GameProfile getProfile(String s) { // Paper - synchronize
|
||||
String s1 = s.toLowerCase(Locale.ROOT);
|
||||
UserCache.UserCacheEntry usercache_usercacheentry = this.c.get(s1);
|
||||
|
||||
@ -152,13 +154,14 @@ public class UserCache {
|
||||
return usercache_usercacheentry == null ? null : usercache_usercacheentry.a();
|
||||
}
|
||||
|
||||
public String[] a() {
|
||||
public synchronized String[] a() { // Paper - synchronize
|
||||
ArrayList arraylist = Lists.newArrayList(this.c.keySet());
|
||||
|
||||
return (String[]) arraylist.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public GameProfile a(UUID uuid) {
|
||||
public GameProfile getProfile(UUID uuid) { return a(uuid); } // Paper - OBFHELPER
|
||||
public synchronized GameProfile a(UUID uuid) { // Paper - synchronize
|
||||
UserCache.UserCacheEntry usercache_usercacheentry = this.d.get(uuid);
|
||||
|
||||
return usercache_usercacheentry == null ? null : usercache_usercacheentry.a();
|
||||
@ -195,21 +198,23 @@ public class UserCache {
|
||||
this.a(usercache_usercacheentry.a(), usercache_usercacheentry.b());
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException filenotfoundexception) {
|
||||
// Spigot Start
|
||||
} catch (com.google.gson.JsonSyntaxException ex) {
|
||||
} catch (Exception ex) {
|
||||
// SportPaper - Catch all UserCache exceptions in one and always delete
|
||||
JsonList.a.warn( "Usercache.json is corrupted or has bad formatting. Deleting it to prevent further issues." );
|
||||
this.g.delete();
|
||||
// Spigot End
|
||||
} catch (JsonParseException ignored) {
|
||||
} finally {
|
||||
IOUtils.closeQuietly(bufferedreader);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Paper start
|
||||
public void c() {
|
||||
c(true);
|
||||
}
|
||||
public void c(boolean asyncSave) {
|
||||
String s = this.b.toJson(this.a(org.spigotmc.SpigotConfig.userCacheCap));
|
||||
Runnable save = () -> {
|
||||
BufferedWriter bufferedwriter = null;
|
||||
|
||||
try {
|
||||
@ -218,10 +223,18 @@ public class UserCache {
|
||||
return;
|
||||
} catch (FileNotFoundException filenotfoundexception) {
|
||||
return;
|
||||
} catch (IOException ignored) {
|
||||
} catch (IOException ioexception) {
|
||||
;
|
||||
} finally {
|
||||
IOUtils.closeQuietly(bufferedwriter);
|
||||
}
|
||||
};
|
||||
if (asyncSave) {
|
||||
MCUtil.scheduleAsyncTask(save);
|
||||
} else {
|
||||
save.run();
|
||||
}
|
||||
// Paper end
|
||||
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
// PaperSpigot end
|
||||
|
||||
// CraftBukkit start
|
||||
@ -438,7 +440,7 @@ public abstract class World implements IBlockAccess {
|
||||
// CraftBukkit start - capture blockstates
|
||||
BlockState blockstate = null;
|
||||
if (this.captureBlockStates) {
|
||||
blockstate = org.bukkit.craftbukkit.block.CraftBlockState.getBlockState(this, blockposition.getX(), blockposition.getY(), blockposition.getZ(), i);
|
||||
blockstate = world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()).getState(); // Paper - use CB getState to get a suitable snapshot
|
||||
this.capturedBlockStates.add(blockstate);
|
||||
}
|
||||
// CraftBukkit end
|
||||
@ -488,7 +490,7 @@ public abstract class World implements IBlockAccess {
|
||||
|
||||
// CraftBukkit start - Split off from original setTypeAndData(int i, int j, int k, Block block, int l, int i1) method in order to directly send client and physic updates
|
||||
public void notifyAndUpdatePhysics(BlockPosition blockposition, Chunk chunk, Block oldBlock, Block newBLock, int flag) {
|
||||
if ((flag & 2) != 0 && (chunk == null || chunk.isReady())) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement
|
||||
if ((flag & 2) != 0 && (!this.isClientSide || (flag & 4) == 0) && (chunk == null || chunk.isReady())) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement
|
||||
this.notify(blockposition);
|
||||
}
|
||||
|
||||
@ -769,6 +771,7 @@ public abstract class World implements IBlockAccess {
|
||||
if (blockposition.getY() >= 256) {
|
||||
blockposition = new BlockPosition(blockposition.getX(), 255, blockposition.getZ());
|
||||
}
|
||||
if (!this.isLoaded(blockposition)) return 0; // Paper
|
||||
|
||||
Chunk chunk = this.getChunkAtWorldCoords(blockposition);
|
||||
|
||||
@ -921,7 +924,8 @@ public abstract class World implements IBlockAccess {
|
||||
int i1 = MathHelper.floor(vec3d.b);
|
||||
int j1 = MathHelper.floor(vec3d.c);
|
||||
BlockPosition blockposition = new BlockPosition(l, i1, j1);
|
||||
IBlockData iblockdata = this.getType(blockposition);
|
||||
IBlockData iblockdata = this.getTypeIfLoaded(blockposition); // SportPaper
|
||||
if (iblockdata == null) return null; // SportPaper
|
||||
Block block = iblockdata.getBlock();
|
||||
|
||||
if ((!flag1 || block.a(this, blockposition, iblockdata) != null) && block.a(iblockdata, flag)) {
|
||||
@ -1023,7 +1027,8 @@ public abstract class World implements IBlockAccess {
|
||||
i1 = MathHelper.floor(vec3d.b) - (enumdirection == EnumDirection.UP ? 1 : 0);
|
||||
j1 = MathHelper.floor(vec3d.c) - (enumdirection == EnumDirection.SOUTH ? 1 : 0);
|
||||
blockposition = new BlockPosition(l, i1, j1);
|
||||
IBlockData iblockdata1 = this.getType(blockposition);
|
||||
IBlockData iblockdata1 = this.getTypeIfLoaded(blockposition); // SportPaper
|
||||
if (iblockdata1 == null) return null; // SportPaper
|
||||
Block block1 = iblockdata1.getBlock();
|
||||
|
||||
if (!flag1 || block1.a(this, blockposition, iblockdata1) != null) {
|
||||
@ -1118,6 +1123,18 @@ public abstract class World implements IBlockAccess {
|
||||
public boolean addEntity(Entity entity, SpawnReason spawnReason) { // Changed signature, added SpawnReason
|
||||
org.spigotmc.AsyncCatcher.catchOp( "entity add"); // Spigot
|
||||
if (entity == null) return false;
|
||||
|
||||
// Workaround for https://bugs.mojang.com/browse/MC-72248
|
||||
// If an EntityFallingBlock spawns inside a block of the same type, the client will ALWAYS remove the block,
|
||||
// whereas the server will only remove it if ticksLived is 0. This creates invisible blocks on the client.
|
||||
// The imperfect workaround is to not spawn the falling block at all if it will cause such a desync.
|
||||
if(entity instanceof EntityFallingBlock && ((EntityFallingBlock) entity).getBlock().getBlock() == this.getType(new BlockPosition(entity)).getBlock()) {
|
||||
EntityFallingBlock fallingBlock = (EntityFallingBlock) entity;
|
||||
if(fallingBlock.ticksLived != 0 && fallingBlock.getBlock().getBlock() == this.getType(new BlockPosition(fallingBlock)).getBlock()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// CraftBukkit end
|
||||
int i = MathHelper.floor(entity.locX / 16.0D);
|
||||
int j = MathHelper.floor(entity.locZ / 16.0D);
|
||||
@ -1372,6 +1389,7 @@ public abstract class World implements IBlockAccess {
|
||||
// Spigot end
|
||||
|
||||
if (entity instanceof EntityItem) return arraylist; // PaperSpigot - Optimize item movement
|
||||
if (entity instanceof EntityArmorStand && !entity.world.paperSpigotConfig.armorStandEntityLookups) return arraylist; // Paper
|
||||
if (entity instanceof EntityArmorStand) return arraylist; // TacoSpigot - Optimize armor stand movement
|
||||
if (entity instanceof EntityTNTPrimed) return arraylist; // TacoSpigot - Optimize tnt entity movement
|
||||
if (entity instanceof EntityFallingBlock) return arraylist; // TacoSpigot - Optimize falling block movement
|
||||
@ -1892,7 +1910,7 @@ public abstract class World implements IBlockAccess {
|
||||
}
|
||||
|
||||
int k = MathHelper.floor(entity.locX / 16.0D);
|
||||
int l = MathHelper.floor(entity.locY / 16.0D);
|
||||
int l = Math.min(15, Math.max(0, MathHelper.floor(entity.locY / 16.0D))); // Paper - stay consistent with chunk add/remove behavior
|
||||
int i1 = MathHelper.floor(entity.locZ / 16.0D);
|
||||
|
||||
if (!entity.ad || entity.ae != k || entity.af != l || entity.ag != i1) {
|
||||
@ -1926,6 +1944,33 @@ public abstract class World implements IBlockAccess {
|
||||
return this.a(axisalignedbb, (Entity) null);
|
||||
}
|
||||
|
||||
// Paper start - Based on method below
|
||||
/**
|
||||
* @param axisalignedbb area to search within
|
||||
* @param entity causing the action ex. block placer
|
||||
* @return if there are no visible players colliding
|
||||
*/
|
||||
public boolean checkNoVisiblePlayerCollisions(AxisAlignedBB axisalignedbb, @Nullable Entity entity) {
|
||||
List list = this.getEntities((Entity) null, axisalignedbb);
|
||||
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
Entity entity1 = (Entity) list.get(i);
|
||||
|
||||
if (entity instanceof EntityPlayer && entity1 instanceof EntityPlayer) {
|
||||
if (!((EntityPlayer) entity).getBukkitEntity().canSee(((EntityPlayer) entity1).getBukkitEntity())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entity1.dead && entity1.blocksEntitySpawning()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// Paper end
|
||||
|
||||
public boolean a(AxisAlignedBB axisalignedbb, Entity entity) {
|
||||
List list = this.getEntities(null, axisalignedbb);
|
||||
|
||||
@ -2115,6 +2160,35 @@ public abstract class World implements IBlockAccess {
|
||||
}
|
||||
// ImHacking end
|
||||
|
||||
// CraftBukkit start
|
||||
public Vec3D getLargestBlockIntersection(AxisAlignedBB aabb, Material material) {
|
||||
int xMin = MathHelper.floor(aabb.a);
|
||||
int xMax = MathHelper.floor(aabb.d + 1.0D);
|
||||
int yMin = MathHelper.floor(aabb.b);
|
||||
int yMax = MathHelper.floor(aabb.e + 1.0D);
|
||||
int zMin = MathHelper.floor(aabb.c);
|
||||
int zMax = MathHelper.floor(aabb.f + 1.0D);
|
||||
double maxVolume = 0;
|
||||
Vec3D block = null;
|
||||
for (int x = xMin; x < xMax; ++x) {
|
||||
for (int y = yMin; y < yMax; ++y) {
|
||||
for (int z = zMin; z < zMax; ++z) {
|
||||
IBlockData type = this.getType(new BlockPosition(x, y, z));
|
||||
if (material == type.getBlock().getMaterial()) {
|
||||
AxisAlignedBB i = new AxisAlignedBB(x, x+1, y, y+1, z, z+1).a(aabb);
|
||||
double volume = (i.d - i.a) * (i.e - i.b) * (i.f - i.c);
|
||||
if(volume > maxVolume) {
|
||||
maxVolume = volume;
|
||||
block = new Vec3D(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
public boolean b(AxisAlignedBB axisalignedbb, Material material) {
|
||||
int i = MathHelper.floor(axisalignedbb.a);
|
||||
int j = MathHelper.floor(axisalignedbb.d + 1.0D);
|
||||
@ -2991,7 +3065,7 @@ public abstract class World implements IBlockAccess {
|
||||
AxisAlignedBB axisalignedbb = flag ? null : block.a(this, blockposition, block.getBlockData());
|
||||
|
||||
// CraftBukkit start - store default return
|
||||
boolean defaultReturn = (axisalignedbb == null || this.a(axisalignedbb, entity)) && (block1.getMaterial() == Material.ORIENTABLE && block == Blocks.ANVIL || block1.getMaterial().isReplaceable() && block.canPlace(this, blockposition, enumdirection, itemstack));
|
||||
boolean defaultReturn = axisalignedbb != null && !this.checkNoVisiblePlayerCollisions(axisalignedbb, entity) ? false : (block1.getMaterial() == Material.ORIENTABLE && block == Blocks.ANVIL ? true : block1.getMaterial().isReplaceable() && block.canPlace(this, blockposition, enumdirection, itemstack)); // Paper - Use our entity search
|
||||
BlockCanBuildEvent event = new BlockCanBuildEvent(this.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftMagicNumbers.getId(block), defaultReturn);
|
||||
this.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
@ -3095,7 +3169,7 @@ public abstract class World implements IBlockAccess {
|
||||
for (EntityHuman player : this.players) {
|
||||
EntityHuman entityhuman1 = player;
|
||||
// CraftBukkit start - Fixed an NPE
|
||||
if (entityhuman1 == null || entityhuman1.dead) {
|
||||
if (entityhuman1 == null || !entityhuman1.ad()) { // CraftBukkit allow for more complex logic by using the "is alive" method
|
||||
continue;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@ -3141,7 +3215,7 @@ public abstract class World implements IBlockAccess {
|
||||
for (EntityHuman player : this.players) {
|
||||
EntityHuman entityhuman1 = player;
|
||||
// CraftBukkit start - Fixed an NPE
|
||||
if (entityhuman1 == null || entityhuman1.dead || !entityhuman1.affectsSpawning) {
|
||||
if (entityhuman1 == null || !entityhuman1.ad() || !entityhuman1.affectsSpawning) { // CraftBukkit allow for more complex logic by using the "is alive" method
|
||||
continue;
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
@ -29,6 +29,7 @@ public class WorldBorder {
|
||||
this.l = 5;
|
||||
}
|
||||
|
||||
public boolean isInBounds(BlockPosition blockposition) { return a(blockposition); } // Paper - OBFHELPER
|
||||
public boolean a(BlockPosition blockposition) {
|
||||
return (double) (blockposition.getX() + 1) > this.b() && (double) blockposition.getX() < this.d() && (double) (blockposition.getZ() + 1) > this.c() && (double) blockposition.getZ() < this.e();
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ public class WorldManager implements IWorldAccess {
|
||||
if (entity instanceof EntityHuman) entityhuman = (EntityHuman) entity;
|
||||
// CraftBukkit end
|
||||
|
||||
PacketPlayOutBlockBreakAnimation packet = null; // SportPaper - cache packet
|
||||
while (iterator.hasNext()) {
|
||||
EntityPlayer entityplayer = (EntityPlayer) iterator.next();
|
||||
|
||||
@ -83,7 +84,10 @@ public class WorldManager implements IWorldAccess {
|
||||
// CraftBukkit end
|
||||
|
||||
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
|
||||
entityplayer.playerConnection.sendPacket(new PacketPlayOutBlockBreakAnimation(i, blockposition, j));
|
||||
// SportPaper start
|
||||
if (packet == null) packet = new PacketPlayOutBlockBreakAnimation(i, blockposition, j);
|
||||
entityplayer.playerConnection.sendPacket(packet);
|
||||
// SportPaper end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -959,15 +959,17 @@ public class WorldServer extends World implements IAsyncTaskHandler {
|
||||
|
||||
this.chunkProvider.saveChunks(flag, iprogressupdate);
|
||||
// CraftBukkit - ArrayList -> Collection
|
||||
Collection arraylist = this.chunkProviderServer.a();
|
||||
/* //Paper start Collection arraylist = chunkproviderserver.a();
|
||||
Iterator iterator = arraylist.iterator();
|
||||
|
||||
for (Object value : arraylist) {
|
||||
Chunk chunk = (Chunk) value;
|
||||
while (iterator.hasNext()) {
|
||||
Chunk chunk = (Chunk) iterator.next();
|
||||
|
||||
if (chunk != null && !this.manager.a(chunk.locX, chunk.locZ)) {
|
||||
this.chunkProviderServer.queueUnload(chunk.locX, chunk.locZ);
|
||||
}
|
||||
}
|
||||
*/// Paper end
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache license, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the license for the specific language governing permissions and
|
||||
* limitations under the license.
|
||||
*/
|
||||
package org.apache.logging.log4j.core.appender;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
import org.apache.logging.log4j.core.Layout;
|
||||
import org.apache.logging.log4j.core.config.plugins.Plugin;
|
||||
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
|
||||
import org.apache.logging.log4j.core.config.plugins.PluginElement;
|
||||
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
|
||||
import org.apache.logging.log4j.core.helpers.Booleans;
|
||||
import org.apache.logging.log4j.core.helpers.Loader;
|
||||
import org.apache.logging.log4j.core.layout.PatternLayout;
|
||||
import org.apache.logging.log4j.util.PropertiesUtil;
|
||||
|
||||
/**
|
||||
* ConsoleAppender appends log events to <code>System.out</code> or
|
||||
* <code>System.err</code> using a layout specified by the user. The
|
||||
* default target is <code>System.out</code>.
|
||||
* @doubt accessing System.out or .err as a byte stream instead of a writer
|
||||
* bypasses the JVM's knowledge of the proper encoding. (RG) Encoding
|
||||
* is handled within the Layout. Typically, a Layout will generate a String
|
||||
* and then call getBytes which may use a configured encoding or the system
|
||||
* default. OTOH, a Writer cannot print byte streams.
|
||||
*/
|
||||
@Plugin(name = "Console", category = "Core", elementType = "appender", printObject = true)
|
||||
public final class ConsoleAppender extends AbstractOutputStreamAppender {
|
||||
|
||||
private static final String JANSI_CLASS = "org.fusesource.jansi.WindowsAnsiOutputStream";
|
||||
private static ConsoleManagerFactory factory = new ConsoleManagerFactory();
|
||||
|
||||
/**
|
||||
* Enumeration of console destinations.
|
||||
*/
|
||||
public enum Target {
|
||||
/** Standard output. */
|
||||
SYSTEM_OUT,
|
||||
/** Standard error output. */
|
||||
SYSTEM_ERR
|
||||
}
|
||||
|
||||
private ConsoleAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
|
||||
final OutputStreamManager manager,
|
||||
final boolean ignoreExceptions) {
|
||||
super(name, layout, filter, ignoreExceptions, true, manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Console Appender.
|
||||
* @param layout The layout to use (required).
|
||||
* @param filter The Filter or null.
|
||||
* @param t The target ("SYSTEM_OUT" or "SYSTEM_ERR"). The default is "SYSTEM_OUT".
|
||||
* @param follow If true will follow changes to the underlying output stream.
|
||||
* @param name The name of the Appender (required).
|
||||
* @param ignore If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise
|
||||
* they are propagated to the caller.
|
||||
* @return The ConsoleAppender.
|
||||
*/
|
||||
@PluginFactory
|
||||
public static ConsoleAppender createAppender(
|
||||
@PluginElement("Layout") Layout<? extends Serializable> layout,
|
||||
@PluginElement("Filters") final Filter filter,
|
||||
@PluginAttribute("target") final String t,
|
||||
@PluginAttribute("name") final String name,
|
||||
@PluginAttribute("follow") final String follow,
|
||||
@PluginAttribute("ignoreExceptions") final String ignore) {
|
||||
if (name == null) {
|
||||
LOGGER.error("No name provided for ConsoleAppender");
|
||||
return null;
|
||||
}
|
||||
if (layout == null) {
|
||||
layout = PatternLayout.createLayout(null, null, null, null, null);
|
||||
}
|
||||
final boolean isFollow = Boolean.parseBoolean(follow);
|
||||
final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
|
||||
final Target target = t == null ? Target.SYSTEM_OUT : Target.valueOf(t);
|
||||
return new ConsoleAppender(name, layout, filter, getManager(isFollow, target, layout), ignoreExceptions);
|
||||
}
|
||||
|
||||
private static OutputStreamManager getManager(final boolean follow, final Target target, final Layout<? extends Serializable> layout) {
|
||||
final String type = target.name();
|
||||
final OutputStream os = getOutputStream(follow, target);
|
||||
return OutputStreamManager.getManager(target.name() + "." + follow, new FactoryData(os, type, layout), factory);
|
||||
}
|
||||
|
||||
private static OutputStream getOutputStream(final boolean follow, final Target target) {
|
||||
final String enc = Charset.defaultCharset().name();
|
||||
PrintStream printStream = null;
|
||||
try {
|
||||
printStream = target == Target.SYSTEM_OUT ?
|
||||
follow ? new PrintStream(new SystemOutStream(), true, enc) : System.out :
|
||||
follow ? new PrintStream(new SystemErrStream(), true, enc) : System.err;
|
||||
} catch (final UnsupportedEncodingException ex) { // should never happen
|
||||
throw new IllegalStateException("Unsupported default encoding " + enc, ex);
|
||||
}
|
||||
final PropertiesUtil propsUtil = PropertiesUtil.getProperties();
|
||||
if (!propsUtil.getStringProperty("os.name").startsWith("Windows") ||
|
||||
propsUtil.getBooleanProperty("log4j.skipJansi")) {
|
||||
return printStream;
|
||||
}
|
||||
try {
|
||||
final ClassLoader loader = Loader.getClassLoader();
|
||||
// We type the parameter as a wildcard to avoid a hard reference to Jansi.
|
||||
final Class<?> clazz = loader.loadClass(JANSI_CLASS);
|
||||
final Constructor<?> constructor = clazz.getConstructor(OutputStream.class);
|
||||
return (OutputStream) constructor.newInstance(printStream);
|
||||
} catch (final ClassNotFoundException cnfe) {
|
||||
LOGGER.debug("Jansi is not installed, cannot find {}", JANSI_CLASS);
|
||||
} catch (final NoSuchMethodException nsme) {
|
||||
LOGGER.warn("{} is missing the proper constructor", JANSI_CLASS);
|
||||
} catch (final Throwable ex) { // CraftBukkit - Exception -> Throwable
|
||||
LOGGER.warn("Unable to instantiate {}", JANSI_CLASS);
|
||||
}
|
||||
return printStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of OutputStream that redirects to the current System.err.
|
||||
*/
|
||||
private static class SystemErrStream extends OutputStream {
|
||||
public SystemErrStream() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// do not close sys err!
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
System.err.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final byte[] b) throws IOException {
|
||||
System.err.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final byte[] b, final int off, final int len)
|
||||
throws IOException {
|
||||
System.err.write(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final int b) {
|
||||
System.err.write(b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of OutputStream that redirects to the current System.out.
|
||||
*/
|
||||
private static class SystemOutStream extends OutputStream {
|
||||
public SystemOutStream() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// do not close sys out!
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
System.out.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final byte[] b) throws IOException {
|
||||
System.out.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final byte[] b, final int off, final int len)
|
||||
throws IOException {
|
||||
System.out.write(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(final int b) throws IOException {
|
||||
System.out.write(b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data to pass to factory method.
|
||||
*/
|
||||
private static class FactoryData {
|
||||
private final OutputStream os;
|
||||
private final String type;
|
||||
private final Layout<? extends Serializable> layout;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param os The OutputStream.
|
||||
* @param type The name of the target.
|
||||
* @param layout A Serializable layout
|
||||
*/
|
||||
public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
|
||||
this.os = os;
|
||||
this.type = type;
|
||||
this.layout = layout;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory to create the Appender.
|
||||
*/
|
||||
private static class ConsoleManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
|
||||
|
||||
/**
|
||||
* Create an OutputStreamManager.
|
||||
* @param name The name of the entity to manage.
|
||||
* @param data The data required to create the entity.
|
||||
* @return The OutputStreamManager
|
||||
*/
|
||||
@Override
|
||||
public OutputStreamManager createManager(final String name, final FactoryData data) {
|
||||
return new OutputStreamManager(data.os, data.type, data.layout);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
package org.bukkit.craftbukkit;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import net.minecraft.server.*;
|
||||
|
||||
@ -13,6 +11,7 @@ import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.craftbukkit.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
@ -79,6 +78,29 @@ public class CraftChunk implements Chunk {
|
||||
return new CraftBlock(this, (getX() << 4) | (x & 0xF), y, (getZ() << 4) | (z & 0xF));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Block> getBlocks(org.bukkit.Material material) {
|
||||
Set<Block> blocks = new HashSet<Block>();
|
||||
|
||||
net.minecraft.server.Block nmsBlock = CraftMagicNumbers.getBlock(material);
|
||||
net.minecraft.server.Chunk chunk = getHandle();
|
||||
|
||||
for(ChunkSection section : chunk.getSections()) {
|
||||
if(section == null || section.a()) continue; // ChunkSection.a() -> true if section is empty
|
||||
|
||||
char[] blockIds = section.getIdArray();
|
||||
for(int i = 0; i < blockIds.length; i++) {
|
||||
// This does a lookup in the block registry, but does not create any objects, so should be pretty efficient
|
||||
IBlockData blockData = net.minecraft.server.Block.d.a(blockIds[i]);
|
||||
if(blockData != null && blockData.getBlock() == nmsBlock) {
|
||||
blocks.add(getBlock(i & 0xf, section.getYPosition() | (i >> 8), (i >> 4) & 0xf));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity[] getEntities() {
|
||||
int count = 0, index = 0;
|
||||
|
@ -82,12 +82,7 @@ import org.bukkit.inventory.ShapedRecipe;
|
||||
import org.bukkit.inventory.ShapelessRecipe;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginLoadOrder;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.ServicesManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
import org.bukkit.plugin.SimpleServicesManager;
|
||||
import org.bukkit.plugin.*;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
import org.bukkit.plugin.messaging.Messenger;
|
||||
import org.bukkit.potion.Potion;
|
||||
@ -649,7 +644,7 @@ public final class CraftServer implements Server {
|
||||
return dispatchCommand(fSender, fCommandLine);
|
||||
}
|
||||
};
|
||||
net.minecraft.server.MinecraftServer.getServer().processQueue.add(wait);
|
||||
net.minecraft.server.MinecraftServer.getServer().addMainThreadTask(wait);
|
||||
try {
|
||||
return wait.get();
|
||||
} catch (InterruptedException e) {
|
||||
@ -731,8 +726,18 @@ public final class CraftServer implements Server {
|
||||
world.tacoSpigotConfig.init(); // TacoSpigot
|
||||
}
|
||||
|
||||
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
|
||||
pluginManager.clearPlugins();
|
||||
commandMap.clearCommands();
|
||||
|
||||
// Paper start
|
||||
for (Plugin plugin : pluginClone) {
|
||||
entityMetadata.removeAll(plugin);
|
||||
worldMetadata.removeAll(plugin);
|
||||
playerMetadata.removeAll(plugin);
|
||||
}
|
||||
// Paper end
|
||||
|
||||
resetRecipes();
|
||||
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
||||
org.github.paperspigot.PaperSpigotConfig.registerCommands(); // PaperSpigot
|
||||
@ -1787,6 +1792,46 @@ public final class CraftServer implements Server {
|
||||
return CraftMagicNumbers.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postToMainThread(Plugin plugin, boolean priority, Runnable task) {
|
||||
getHandle().getServer().addMainThreadTask(priority, wrapTask(plugin, task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runOnMainThread(Plugin plugin, boolean priority, Runnable task) {
|
||||
task = wrapTask(plugin, task);
|
||||
|
||||
if(getHandle().getServer().isMainThread()) {
|
||||
task.run();
|
||||
return true;
|
||||
} else {
|
||||
postToMainThread(plugin, priority, task);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable wrapTask(final Plugin plugin, final Runnable task) {
|
||||
if(!plugin.isEnabled()) {
|
||||
throw new IllegalPluginAccessException("Plugin attempted to register task while disabled");
|
||||
}
|
||||
|
||||
class Wrapped implements Runnable {
|
||||
@Override public void run() {
|
||||
try {
|
||||
task.run();
|
||||
} catch(Throwable throwable) {
|
||||
plugin.getLogger().log(
|
||||
Level.SEVERE,
|
||||
"Exception running task from plugin " + plugin.getDescription().getFullName(),
|
||||
throwable
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return task instanceof Wrapped ? task : new Wrapped();
|
||||
}
|
||||
|
||||
private final Spigot spigot = new Spigot()
|
||||
{
|
||||
|
||||
|
@ -55,6 +55,7 @@ import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.messaging.StandardMessenger;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.github.paperspigot.PaperSpigotConfig;
|
||||
|
||||
public class CraftWorld implements World {
|
||||
public static final int CUSTOM_DIMENSION_OFFSET = 10;
|
||||
@ -76,6 +77,26 @@ public class CraftWorld implements World {
|
||||
private int chunkLoadCount = 0;
|
||||
private int chunkGCTickCount;
|
||||
|
||||
// Paper start - Provide fast information methods
|
||||
public int getEntityCount() {
|
||||
return world.entityList.size();
|
||||
}
|
||||
public int getTileEntityCount() {
|
||||
// We don't use the full world tile entity list, so we must iterate chunks
|
||||
int size = 0;
|
||||
for (net.minecraft.server.Chunk chunk : world.chunkProviderServer.chunks.values()) {
|
||||
size += chunk.tileEntities.size();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
public int getChunkCount() {
|
||||
return world.chunkProviderServer.chunks.size();
|
||||
}
|
||||
public int getPlayerCount() {
|
||||
return world.players.size();
|
||||
}
|
||||
// Paper end
|
||||
|
||||
private static final Random rand = new Random();
|
||||
|
||||
public CraftWorld(WorldServer world, ChunkGenerator gen, Environment env) {
|
||||
@ -89,6 +110,32 @@ public class CraftWorld implements World {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ticking = false;
|
||||
|
||||
public boolean isTicking() {
|
||||
return ticking;
|
||||
}
|
||||
|
||||
public boolean checkTicking() {
|
||||
boolean shouldTick = PaperSpigotConfig.tickEmptyWorlds || hasPlayers();
|
||||
if(ticking) {
|
||||
if(!shouldTick) { // Empty
|
||||
ticking = false;
|
||||
world.getServer().getLogger().info("Stopping world " + getName());
|
||||
getHandle().chunkProviderServer.unloadAllChunks();
|
||||
}
|
||||
} else if(shouldTick) {
|
||||
ticking = true;
|
||||
world.getServer().getLogger().info("Starting world " + getName());
|
||||
setKeepSpawnInMemory(getKeepSpawnInMemory());
|
||||
}
|
||||
return ticking;
|
||||
}
|
||||
|
||||
public boolean hasPlayers() {
|
||||
return getPlayerCount() > 0;
|
||||
}
|
||||
|
||||
public Block getBlockAt(int x, int y, int z) {
|
||||
return getChunkAt(x >> 4, z >> 4).getBlock(x & 0xF, y, z & 0xF);
|
||||
}
|
||||
@ -299,7 +346,6 @@ public class CraftWorld implements World {
|
||||
return world.chunkProviderServer.getChunkAt(x, z) != null;
|
||||
}
|
||||
|
||||
world.chunkProviderServer.unloadQueue.remove(LongHash.toLong(x, z)); // TacoSpigot - invoke LongHash directly
|
||||
net.minecraft.server.Chunk chunk = world.chunkProviderServer.chunks.get(LongHash.toLong(x, z));
|
||||
|
||||
if (chunk == null) {
|
||||
@ -309,6 +355,7 @@ public class CraftWorld implements World {
|
||||
chunkLoadPostProcess(chunk, x, z);
|
||||
world.timings.syncChunkLoadTimer.stopTiming(); // Spigot
|
||||
}
|
||||
world.chunkProviderServer.unloadQueue.remove(LongHash.toLong(x, z));
|
||||
return chunk != null;
|
||||
}
|
||||
|
||||
@ -906,7 +953,7 @@ public class CraftWorld implements World {
|
||||
Validate.isTrue(material.isBlock(), "Material must be a block");
|
||||
|
||||
double x = location.getBlockX() + 0.5;
|
||||
double y = location.getBlockY() + 0.5;
|
||||
double y = location.getBlockY();
|
||||
double z = location.getBlockZ() + 0.5;
|
||||
|
||||
// PaperSpigot start - Add FallingBlock source location API
|
||||
@ -940,6 +987,9 @@ public class CraftWorld implements World {
|
||||
// order is important for some of these
|
||||
if (Boat.class.isAssignableFrom(clazz)) {
|
||||
entity = new EntityBoat(world, x, y, z);
|
||||
} else if (org.bukkit.entity.Item.class.isAssignableFrom(clazz)) {
|
||||
entity = new EntityItem(world, x, y, z, new net.minecraft.server.ItemStack(net.minecraft.server.Item.getItemOf(net.minecraft.server.Blocks.DIRT)));
|
||||
// Paper end
|
||||
} else if (FallingBlock.class.isAssignableFrom(clazz)) {
|
||||
x = location.getBlockX();
|
||||
y = location.getBlockY();
|
||||
|
@ -1,9 +1,6 @@
|
||||
package org.bukkit.craftbukkit.chunkio;
|
||||
|
||||
import net.minecraft.server.Chunk;
|
||||
import net.minecraft.server.ChunkProviderServer;
|
||||
import net.minecraft.server.ChunkRegionLoader;
|
||||
import net.minecraft.server.World;
|
||||
import net.minecraft.server.*;
|
||||
import org.bukkit.craftbukkit.util.AsynchronousExecutor;
|
||||
|
||||
public class ChunkIOExecutor {
|
||||
@ -13,7 +10,7 @@ public class ChunkIOExecutor {
|
||||
private static final AsynchronousExecutor<QueuedChunk, Chunk, Runnable, RuntimeException> instance = new AsynchronousExecutor<>(new ChunkIOProvider(), BASE_THREADS);
|
||||
|
||||
public static Chunk syncChunkLoad(World world, ChunkRegionLoader loader, ChunkProviderServer provider, int x, int z) {
|
||||
return instance.getSkipQueue(new QueuedChunk(x, z, loader, world, provider));
|
||||
return MCUtil.ensureMain("Async Chunk Load", () -> instance.getSkipQueue(new QueuedChunk(x, z, loader, world, provider))); // Paper
|
||||
}
|
||||
|
||||
public static void queueChunkLoad(World world, ChunkRegionLoader loader, ChunkProviderServer provider, int x, int z, Runnable runnable) {
|
||||
|
@ -2,6 +2,7 @@ package org.bukkit.craftbukkit.chunkio;
|
||||
|
||||
import java.io.IOException;
|
||||
import net.minecraft.server.Chunk;
|
||||
import net.minecraft.server.ChunkCoordIntPair;
|
||||
import net.minecraft.server.ChunkRegionLoader;
|
||||
import net.minecraft.server.NBTTagCompound;
|
||||
|
||||
@ -33,8 +34,8 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider<QueuedChu
|
||||
|
||||
// sync stuff
|
||||
public void callStage2(QueuedChunk queuedChunk, Chunk chunk) throws RuntimeException {
|
||||
if (chunk == null) {
|
||||
// If the chunk loading failed just do it synchronously (may generate)
|
||||
if (chunk == null || queuedChunk.provider.chunks.containsKey(ChunkCoordIntPair.a(queuedChunk.x, queuedChunk.z))) { // Paper - also call original if it was already loaded
|
||||
// If the chunk loading failed (or was already loaded for some reason) just do it synchronously (may generate)
|
||||
queuedChunk.provider.originalGetChunkAt(queuedChunk.x, queuedChunk.z);
|
||||
return;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class ConsoleCommandCompleter implements Completer {
|
||||
return server.getCommandMap().tabComplete(server.getConsoleSender(), buffer);
|
||||
}
|
||||
};
|
||||
this.server.getServer().processQueue.add(waitable);
|
||||
this.server.getServer().addMainThreadTask(waitable);
|
||||
try {
|
||||
List<String> offers = waitable.get();
|
||||
if (offers == null) {
|
||||
|
@ -64,6 +64,16 @@ public class CraftFish extends AbstractProjectile implements Fish {
|
||||
this.biteChance = chance;
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@Override
|
||||
public void remove() {
|
||||
super.remove();
|
||||
if (getHandle().owner != null) {
|
||||
getHandle().owner.hookedFish = null;
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@Deprecated
|
||||
public LivingEntity _INVALID_getShooter() {
|
||||
return (LivingEntity) getShooter();
|
||||
|
@ -1,10 +1,7 @@
|
||||
package org.bukkit.craftbukkit.event;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Functions;
|
||||
@ -484,6 +481,10 @@ public class CraftEventFactory {
|
||||
blockDamage = null;
|
||||
if (source == DamageSource.CACTUS) {
|
||||
cause = DamageCause.CONTACT;
|
||||
} else if (source == DamageSource.FIRE) {
|
||||
cause = DamageCause.FIRE;
|
||||
} else if (source == DamageSource.LAVA) {
|
||||
cause = DamageCause.LAVA;
|
||||
} else {
|
||||
throw new RuntimeException(String.format("Unhandled damage of %s by %s from %s", entity, damager, source.translationIndex)); // Spigot
|
||||
}
|
||||
@ -515,6 +516,8 @@ public class CraftEventFactory {
|
||||
DamageCause cause = null;
|
||||
if (source == DamageSource.FIRE) {
|
||||
cause = DamageCause.FIRE;
|
||||
} else if (source == DamageSource.LAVA) {
|
||||
cause = DamageCause.LAVA;
|
||||
} else if (source == DamageSource.STARVE) {
|
||||
cause = DamageCause.STARVATION;
|
||||
} else if (source == DamageSource.WITHER) {
|
||||
@ -982,4 +985,59 @@ public class CraftEventFactory {
|
||||
return event;
|
||||
}
|
||||
// PaperSpigot end
|
||||
|
||||
public static BlockPistonEvent callBlockPistonEvent(final World world, BlockPosition pos, EnumDirection facing, boolean extending) {
|
||||
// When retracting, PistonExtendsChecker expects the piston arm to already be
|
||||
// removed, so we have to temporarily remove it or it will get in the way.
|
||||
BlockPosition extensionPos = pos.shift(facing);
|
||||
IBlockData extensionData = null;
|
||||
if(!extending) {
|
||||
extensionData = world.getType(extensionPos);
|
||||
world.setTypeAndData(extensionPos, Blocks.AIR.getBlockData(), 0);
|
||||
}
|
||||
|
||||
// This thing searches for all the blocks that will be moved. We have to use it twice,
|
||||
// because it's too late to cancel by the time NMS calls it. A potential optimization
|
||||
// would be to save this result and reuse it in the NMS code, but that's probably not
|
||||
// worth the messy diff.
|
||||
PistonExtendsChecker checker = new PistonExtendsChecker(world, pos, facing, extending);
|
||||
boolean moved = checker.a();
|
||||
|
||||
if(extensionData != null) {
|
||||
world.setTypeAndData(extensionPos, extensionData, 0);
|
||||
}
|
||||
|
||||
// This means vanilla mechanics will obstruct the piston, so no need for any event.
|
||||
if(!moved) return null;
|
||||
|
||||
// A sort of lazy list that avoids wrapping blocks until needed
|
||||
final List movedBlocks = checker.getMovedBlocks();
|
||||
final List brokenBlocks = checker.getBrokenBlocks();
|
||||
List<org.bukkit.block.Block> blocks = new AbstractList<Block>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return movedBlocks.size() + brokenBlocks.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.block.Block get(int index) {
|
||||
if (index >= size() || index < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException(index);
|
||||
}
|
||||
BlockPosition pos = (BlockPosition) (index < movedBlocks.size() ? movedBlocks.get(index) : brokenBlocks.get(index - movedBlocks.size()));
|
||||
return world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
};
|
||||
|
||||
org.bukkit.block.Block block = world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ());
|
||||
BlockPistonEvent event;
|
||||
if(extending) {
|
||||
event = new BlockPistonExtendEvent(block, blocks, CraftBlock.notchToBlockFace(facing));
|
||||
} else {
|
||||
event = new BlockPistonRetractEvent(block, blocks, CraftBlock.notchToBlockFace(facing.opposite()));
|
||||
}
|
||||
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
@ -196,6 +196,13 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta {
|
||||
return super.isEmpty() && patterns.isEmpty() && base == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CraftMetaBanner clone() {
|
||||
CraftMetaBanner meta = (CraftMetaBanner) super.clone();
|
||||
meta.base = this.base;
|
||||
meta.patterns = this.patterns;
|
||||
return meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean applicableTo(Material type) {
|
||||
|
@ -47,7 +47,7 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
|
||||
@ItemMetaKey.Specific(ItemMetaKey.Specific.To.NBT)
|
||||
static final ItemMetaKey BLOCK_ENTITY_TAG = new ItemMetaKey("BlockEntityTag");
|
||||
|
||||
final Material material;
|
||||
Material material;
|
||||
NBTTagCompound blockEntityTag;
|
||||
|
||||
CraftMetaBlockState(CraftMetaItem meta, Material material) {
|
||||
@ -335,4 +335,12 @@ public class CraftMetaBlockState extends CraftMetaItem implements BlockStateMeta
|
||||
blockEntityTag = new NBTTagCompound();
|
||||
te.b(blockEntityTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CraftMetaBlockState clone() {
|
||||
CraftMetaBlockState meta = (CraftMetaBlockState) super.clone();
|
||||
meta.material = this.material;
|
||||
meta.blockEntityTag = this.blockEntityTag;
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ import net.minecraft.server.IAttribute;
|
||||
* <li> SerializableMeta.Deserializers deserializer()
|
||||
*/
|
||||
@DelegateDeserialization(CraftMetaItem.SerializableMeta.class)
|
||||
class CraftMetaItem implements ItemMeta, Repairable {
|
||||
public class CraftMetaItem implements ItemMeta, Repairable {
|
||||
|
||||
static class ItemMetaKey {
|
||||
|
||||
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Daniel Ennis (Aikar) MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.bukkit.craftbukkit.scheduler;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.github.paperspigot.ServerSchedulerReportingWrapper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CraftAsyncScheduler extends CraftScheduler {
|
||||
|
||||
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(
|
||||
4, Integer.MAX_VALUE,30L, TimeUnit.SECONDS, new SynchronousQueue<>(),
|
||||
new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build());
|
||||
private final Executor management = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder()
|
||||
.setNameFormat("Craft Async Scheduler Management Thread").build());
|
||||
private final List<CraftTask> temp = new ArrayList<>();
|
||||
|
||||
CraftAsyncScheduler() {
|
||||
super(true);
|
||||
executor.allowCoreThreadTimeOut(true);
|
||||
executor.prestartAllCoreThreads();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelTask(int taskId) {
|
||||
this.management.execute(() -> this.removeTask(taskId));
|
||||
}
|
||||
|
||||
private synchronized void removeTask(int taskId) {
|
||||
parsePending();
|
||||
this.pending.removeIf((task) -> {
|
||||
if (task.getTaskId() == taskId) {
|
||||
task.cancel0();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mainThreadHeartbeat(int currentTick) {
|
||||
this.currentTick = currentTick;
|
||||
this.management.execute(() -> this.runTasks(currentTick));
|
||||
}
|
||||
|
||||
private synchronized void runTasks(int currentTick) {
|
||||
parsePending();
|
||||
while (!this.pending.isEmpty() && this.pending.peek().getNextRun() <= currentTick) {
|
||||
CraftTask task = this.pending.remove();
|
||||
if (executeTask(task)) {
|
||||
final long period = task.getPeriod();
|
||||
if (period > 0) {
|
||||
task.setNextRun(currentTick + period);
|
||||
temp.add(task);
|
||||
}
|
||||
}
|
||||
parsePending();
|
||||
}
|
||||
this.pending.addAll(temp);
|
||||
temp.clear();
|
||||
}
|
||||
|
||||
private boolean executeTask(CraftTask task) {
|
||||
if (isValid(task)) {
|
||||
this.runners.put(task.getTaskId(), task);
|
||||
this.executor.execute(new ServerSchedulerReportingWrapper(task));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void cancelTasks(Plugin plugin) {
|
||||
parsePending();
|
||||
for (Iterator<CraftTask> iterator = this.pending.iterator(); iterator.hasNext(); ) {
|
||||
CraftTask task = iterator.next();
|
||||
if (task.getTaskId() != -1 && (plugin == null || task.getOwner().equals(plugin))) {
|
||||
task.cancel0();
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void cancelAllTasks() {
|
||||
cancelTasks(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Task is not cancelled
|
||||
* @param runningTask
|
||||
* @return
|
||||
*/
|
||||
static boolean isValid(CraftTask runningTask) {
|
||||
return runningTask.getPeriod() >= CraftTask.NO_REPEATING;
|
||||
}
|
||||
}
|
@ -21,6 +21,9 @@ import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.bukkit.scheduler.BukkitWorker;
|
||||
import org.github.paperspigot.ServerSchedulerReportingWrapper;
|
||||
import org.github.paperspigot.event.ServerExceptionEvent;
|
||||
import org.github.paperspigot.exception.ServerSchedulerException;
|
||||
|
||||
/**
|
||||
* The fundamental concepts for this implementation:
|
||||
@ -32,7 +35,7 @@ import org.bukkit.scheduler.BukkitWorker;
|
||||
* <li>Changing the period on a task is delicate.
|
||||
* Any future task needs to notify waiting threads.
|
||||
* Async tasks must be synchronized to make sure that any thread that's finishing will remove itself from {@link #runners}.
|
||||
* Another utility method is provided for this, {@link #cancelTask(int)}</li>
|
||||
* Another utility method is provided for this, {@link #cancelTask(CraftTask)}</li>
|
||||
* <li>{@link #runners} provides a moderately up-to-date view of active tasks.
|
||||
* If the linked head to tail set is read, all remaining tasks that were active at the time execution started will be located in runners.</li>
|
||||
* <li>Async tasks are responsible for removing themselves from runners</li>
|
||||
@ -47,28 +50,32 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
*/
|
||||
private final AtomicInteger ids = new AtomicInteger(1);
|
||||
/**
|
||||
* Current head of linked-list. This reference is always stale, {@code CraftTask#next} is the live reference.
|
||||
* Current head of linked-list. This reference is always stale, {@link CraftTask#next} is the live reference.
|
||||
*/
|
||||
private volatile CraftTask head = new CraftTask();
|
||||
/**
|
||||
* Tail of a linked-list. AtomicReference only matters when adding to queue
|
||||
*/
|
||||
private final AtomicReference<CraftTask> tail = new AtomicReference<>(head);
|
||||
private final AtomicReference<CraftTask> tail = new AtomicReference<CraftTask>(head);
|
||||
/**
|
||||
* Main thread logic only
|
||||
*/
|
||||
private final PriorityQueue<CraftTask> pending = new PriorityQueue<>(10,
|
||||
(o1, o2) -> (int) (o1.getNextRun() - o2.getNextRun()));
|
||||
final PriorityQueue<CraftTask> pending = new PriorityQueue<CraftTask>(10, // Paper
|
||||
new Comparator<CraftTask>() {
|
||||
public int compare(final CraftTask o1, final CraftTask o2) {
|
||||
return (int) (o1.getNextRun() - o2.getNextRun());
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Main thread logic only
|
||||
*/
|
||||
private final List<CraftTask> temp = new ArrayList<>();
|
||||
private final List<CraftTask> temp = new ArrayList<CraftTask>();
|
||||
/**
|
||||
* These are tasks that are currently active. It's provided for 'viewing' the current state.
|
||||
*/
|
||||
private final ConcurrentHashMap<Integer, CraftTask> runners = new ConcurrentHashMap<>();
|
||||
private volatile int currentTick = -1;
|
||||
private final Executor executor = Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build()); // Spigot
|
||||
final ConcurrentHashMap<Integer, CraftTask> runners = new ConcurrentHashMap<Integer, CraftTask>(); // Paper
|
||||
volatile int currentTick = -1; // Paper
|
||||
//private final Executor executor = Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %1$d").build()); // Spigot // Paper - moved to AsyncScheduler
|
||||
private CraftAsyncDebugger debugHead = new CraftAsyncDebugger(-1, null, null) {@Override StringBuilder debugTo(StringBuilder string) {return string;}};
|
||||
private CraftAsyncDebugger debugTail = debugHead;
|
||||
private static final int RECENT_TICKS;
|
||||
@ -77,6 +84,23 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
RECENT_TICKS = 30;
|
||||
}
|
||||
|
||||
// Paper start
|
||||
private final CraftScheduler asyncScheduler;
|
||||
private final boolean isAsyncScheduler;
|
||||
public CraftScheduler() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public CraftScheduler(boolean isAsync) {
|
||||
this.isAsyncScheduler = isAsync;
|
||||
if (isAsync) {
|
||||
this.asyncScheduler = this;
|
||||
} else {
|
||||
this.asyncScheduler = new CraftAsyncScheduler();
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
|
||||
public int scheduleSyncDelayedTask(final Plugin plugin, final Runnable task) {
|
||||
return this.scheduleSyncDelayedTask(plugin, task, 0l);
|
||||
}
|
||||
@ -143,12 +167,12 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
} else if (period < -1l) {
|
||||
period = -1l;
|
||||
}
|
||||
return handle(new CraftAsyncTask(runners, plugin, runnable, nextId(), period), delay);
|
||||
return handle(new CraftAsyncTask(this.asyncScheduler.runners, plugin, runnable, nextId(), period), delay); // Paper
|
||||
}
|
||||
|
||||
public <T> Future<T> callSyncMethod(final Plugin plugin, final Callable<T> task) {
|
||||
validate(plugin, task);
|
||||
final CraftFuture<T> future = new CraftFuture<>(task, plugin, nextId());
|
||||
final CraftFuture<T> future = new CraftFuture<T>(task, plugin, nextId());
|
||||
handle(future, 0l);
|
||||
return future;
|
||||
}
|
||||
@ -157,6 +181,11 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
if (taskId <= 0) {
|
||||
return;
|
||||
}
|
||||
// Paper start
|
||||
if (!this.isAsyncScheduler) {
|
||||
this.asyncScheduler.cancelTask(taskId);
|
||||
}
|
||||
// Paper end
|
||||
CraftTask task = runners.get(taskId);
|
||||
if (task != null) {
|
||||
task.cancel0();
|
||||
@ -196,6 +225,11 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
|
||||
public void cancelTasks(final Plugin plugin) {
|
||||
Validate.notNull(plugin, "Cannot cancel tasks of null plugin");
|
||||
// Paper start
|
||||
if (!this.isAsyncScheduler) {
|
||||
this.asyncScheduler.cancelTasks(plugin);
|
||||
}
|
||||
// Paper end
|
||||
final CraftTask task = new CraftTask(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
@ -233,18 +267,25 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
}
|
||||
|
||||
public void cancelAllTasks() {
|
||||
// Paper start
|
||||
if (!this.isAsyncScheduler) {
|
||||
this.asyncScheduler.cancelAllTasks();
|
||||
}
|
||||
// Paper end
|
||||
final CraftTask task = new CraftTask(
|
||||
() -> {
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
Iterator<CraftTask> it = CraftScheduler.this.runners.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
CraftTask task1 = it.next();
|
||||
task1.cancel0();
|
||||
if (task1.isSync()) {
|
||||
CraftTask task = it.next();
|
||||
task.cancel0();
|
||||
if (task.isSync()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
CraftScheduler.this.pending.clear();
|
||||
CraftScheduler.this.temp.clear();
|
||||
}
|
||||
}){{this.timings=co.aikar.timings.SpigotTimings.getCancelTasksTimer();}}; // Spigot
|
||||
handle(task, 0l);
|
||||
for (CraftTask taskPending = head.getNext(); taskPending != null; taskPending = taskPending.getNext()) {
|
||||
@ -259,6 +300,13 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
}
|
||||
|
||||
public boolean isCurrentlyRunning(final int taskId) {
|
||||
// Paper start
|
||||
if (!isAsyncScheduler) {
|
||||
if (this.asyncScheduler.isCurrentlyRunning(taskId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Paper end
|
||||
final CraftTask task = runners.get(taskId);
|
||||
if (task == null || task.isSync()) {
|
||||
return false;
|
||||
@ -273,6 +321,11 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
if (taskId <= 0) {
|
||||
return false;
|
||||
}
|
||||
// Paper start
|
||||
if (!this.isAsyncScheduler && this.asyncScheduler.isQueued(taskId)) {
|
||||
return true;
|
||||
}
|
||||
// Paper end
|
||||
for (CraftTask task = head.getNext(); task != null; task = task.getNext()) {
|
||||
if (task.getTaskId() == taskId) {
|
||||
return task.getPeriod() >= -1l; // The task will run
|
||||
@ -283,7 +336,13 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
}
|
||||
|
||||
public List<BukkitWorker> getActiveWorkers() {
|
||||
final ArrayList<BukkitWorker> workers = new ArrayList<>();
|
||||
// Paper start
|
||||
if (!isAsyncScheduler) {
|
||||
//noinspection TailRecursion
|
||||
return this.asyncScheduler.getActiveWorkers();
|
||||
}
|
||||
// Paper end
|
||||
final ArrayList<BukkitWorker> workers = new ArrayList<BukkitWorker>();
|
||||
for (final CraftTask taskObj : runners.values()) {
|
||||
// Iterator will be a best-effort (may fail to grab very new values) if called from an async thread
|
||||
if (taskObj.isSync()) {
|
||||
@ -299,7 +358,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
}
|
||||
|
||||
public List<BukkitTask> getPendingTasks() {
|
||||
final ArrayList<CraftTask> truePending = new ArrayList<>();
|
||||
final ArrayList<CraftTask> truePending = new ArrayList<CraftTask>();
|
||||
for (CraftTask task = head.getNext(); task != null; task = task.getNext()) {
|
||||
if (task.getTaskId() != -1) {
|
||||
// -1 is special code
|
||||
@ -307,7 +366,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
}
|
||||
}
|
||||
|
||||
final ArrayList<BukkitTask> pending = new ArrayList<>();
|
||||
final ArrayList<BukkitTask> pending = new ArrayList<BukkitTask>();
|
||||
for (CraftTask task : runners.values()) {
|
||||
if (task.getPeriod() >= -1l) {
|
||||
pending.add(task);
|
||||
@ -319,6 +378,11 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
pending.add(task);
|
||||
}
|
||||
}
|
||||
// Paper start
|
||||
if (!this.isAsyncScheduler) {
|
||||
pending.addAll(this.asyncScheduler.getPendingTasks());
|
||||
}
|
||||
// Paper end
|
||||
return pending;
|
||||
}
|
||||
|
||||
@ -326,6 +390,11 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
* This method is designed to never block or wait for locks; an immediate execution of all current tasks.
|
||||
*/
|
||||
public void mainThreadHeartbeat(final int currentTick) {
|
||||
// Paper start
|
||||
if (!this.isAsyncScheduler) {
|
||||
this.asyncScheduler.mainThreadHeartbeat(currentTick);
|
||||
}
|
||||
// Paper end
|
||||
this.currentTick = currentTick;
|
||||
final List<CraftTask> temp = this.temp;
|
||||
parsePending();
|
||||
@ -342,18 +411,24 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
try {
|
||||
task.run();
|
||||
} catch (final Throwable throwable) {
|
||||
task.getOwner().getLogger().log(
|
||||
Level.WARNING,
|
||||
String.format(
|
||||
// Paper start
|
||||
String msg = String.format(
|
||||
"Task #%s for %s generated an exception",
|
||||
task.getTaskId(),
|
||||
task.getOwner().getDescription().getFullName()),
|
||||
task.getOwner().getDescription().getFullName());
|
||||
task.getOwner().getLogger().log(
|
||||
Level.WARNING,
|
||||
msg,
|
||||
throwable);
|
||||
task.getOwner().getServer().getPluginManager().callEvent(
|
||||
new ServerExceptionEvent(new ServerSchedulerException(msg, throwable, task))
|
||||
);
|
||||
// Paper end
|
||||
}
|
||||
parsePending();
|
||||
} else {
|
||||
debugTail = debugTail.setNext(new CraftAsyncDebugger(currentTick + RECENT_TICKS, task.getOwner(), task.getTaskClass()));
|
||||
executor.execute(task);
|
||||
task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to Paper"); // Paper
|
||||
// We don't need to parse pending
|
||||
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
|
||||
}
|
||||
@ -370,7 +445,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
debugHead = debugHead.getNextHead(currentTick);
|
||||
}
|
||||
|
||||
private void addTask(final CraftTask task) {
|
||||
protected void addTask(final CraftTask task) {
|
||||
final AtomicReference<CraftTask> tail = this.tail;
|
||||
CraftTask tailTask = tail.get();
|
||||
while (!tail.compareAndSet(tailTask, task)) {
|
||||
@ -379,7 +454,13 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
tailTask.setNext(task);
|
||||
}
|
||||
|
||||
private CraftTask handle(final CraftTask task, final long delay) {
|
||||
protected CraftTask handle(final CraftTask task, final long delay) { // Paper
|
||||
// Paper start
|
||||
if (!this.isAsyncScheduler && !task.isSync()) {
|
||||
this.asyncScheduler.handle(task, delay);
|
||||
return task;
|
||||
}
|
||||
// Paper end
|
||||
task.setNextRun(currentTick + delay);
|
||||
addTask(task);
|
||||
return task;
|
||||
@ -397,7 +478,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
return ids.incrementAndGet();
|
||||
}
|
||||
|
||||
private void parsePending() {
|
||||
void parsePending() { // Paper
|
||||
CraftTask head = this.head;
|
||||
CraftTask task = head.getNext();
|
||||
CraftTask lastTask = head;
|
||||
|
@ -10,6 +10,11 @@ import org.bukkit.scheduler.BukkitTask;
|
||||
public class CraftTask implements BukkitTask, Runnable { // Spigot
|
||||
|
||||
private volatile CraftTask next = null;
|
||||
public static final int ERROR = 0;
|
||||
public static final int NO_REPEATING = -1;
|
||||
public static final int CANCEL = -2;
|
||||
public static final int PROCESS_FOR_FUTURE = -3;
|
||||
public static final int DONE_FOR_FUTURE = -4;
|
||||
/**
|
||||
* -1 means no repeating <br>
|
||||
* -2 means cancel <br>
|
||||
|
@ -144,8 +144,14 @@ public final class CraftChatMessage {
|
||||
public static String fromComponent(IChatBaseComponent component, EnumChatFormat defaultColor) {
|
||||
if (component == null) return "";
|
||||
StringBuilder out = new StringBuilder();
|
||||
// SportPaper - limit iterations to 2
|
||||
byte iterations = 0;
|
||||
|
||||
for (IChatBaseComponent c : (Iterable<IChatBaseComponent>) component) {
|
||||
if (++iterations > 2) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (IChatBaseComponent c : component) {
|
||||
ChatModifier modi = c.getChatModifier();
|
||||
out.append(modi.getColor() == null ? defaultColor : modi.getColor());
|
||||
if (modi.isBold()) {
|
||||
|
@ -8,7 +8,7 @@ import java.util.TreeSet;
|
||||
|
||||
public class HashTreeSet<V> implements Set<V> {
|
||||
|
||||
private HashSet<V> hash = new HashSet<>();
|
||||
private Set<V> hash = new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<V>(); //Paper - Replace java.util.HashSet with ObjectOpenHashSet
|
||||
private TreeSet<V> tree = new TreeSet<>();
|
||||
|
||||
public HashTreeSet() {
|
||||
|
@ -146,13 +146,13 @@ public class PaperSpigotConfig
|
||||
public static double babyZombieMovementSpeed;
|
||||
private static void babyZombieMovementSpeed()
|
||||
{
|
||||
babyZombieMovementSpeed = getDouble( "settings.baby-zombie-movement-speed", 0.5D ); // Player moves at 0.1F, for reference
|
||||
babyZombieMovementSpeed = getDouble( "baby-zombie-movement-speed", 0.5D ); // Player moves at 0.1F, for reference
|
||||
}
|
||||
|
||||
public static boolean interactLimitEnabled;
|
||||
private static void interactLimitEnabled()
|
||||
{
|
||||
interactLimitEnabled = getBoolean( "settings.limit-player-interactions", true );
|
||||
interactLimitEnabled = getBoolean( "limit-player-interactions", true );
|
||||
if ( !interactLimitEnabled )
|
||||
{
|
||||
Bukkit.getLogger().log( Level.INFO, "Disabling player interaction limiter, your server may be more vulnerable to malicious users" );
|
||||
@ -223,12 +223,38 @@ public class PaperSpigotConfig
|
||||
warnForExcessiveVelocity = getBoolean("warnWhenSettingExcessiveVelocity", true);
|
||||
}
|
||||
|
||||
public static int regionFileCacheSize = 256;
|
||||
private static void regionFileCacheSize() {
|
||||
regionFileCacheSize = getInt("region-file-cache-size", 256);
|
||||
}
|
||||
|
||||
public static boolean saveEmptyScoreboardTeams;
|
||||
private static void saveEmptyScoreboardTeams() {
|
||||
saveEmptyScoreboardTeams = getBoolean("save-empty-scoreboard-teams", false);
|
||||
}
|
||||
|
||||
// KigPaper start
|
||||
public static int tabSpamIncrement = 10;
|
||||
public static int tabSpamLimit = 500;
|
||||
private static void tabSpamLimiters() {
|
||||
tabSpamIncrement = getInt("spam-limiter.tab-spam-increment", tabSpamIncrement);
|
||||
tabSpamLimit = getInt("spam-limiter.tab-spam-limit", tabSpamLimit);
|
||||
}
|
||||
|
||||
public static boolean includeRandomnessInArrowTrajectory = false;
|
||||
private static void includeRandomnessInArrowTrajectory() {
|
||||
includeRandomnessInArrowTrajectory = getBoolean("include-randomness-in-arrow-trajectory", includeRandomnessInArrowTrajectory);
|
||||
}
|
||||
|
||||
public static boolean includeRandomnessInArrowDamage = true;
|
||||
private static void includeRandomnessInArrowDamage() {
|
||||
includeRandomnessInArrowDamage = getBoolean("include-randomness-in-arrow-damage", includeRandomnessInArrowDamage);
|
||||
}
|
||||
|
||||
public static boolean tickEmptyWorlds = true;
|
||||
private static void tickEmptyWorlds() {
|
||||
tickEmptyWorlds = getBoolean("tick-empty-worlds", tickEmptyWorlds);
|
||||
}
|
||||
|
||||
public static boolean betterVehicleHitboxes;
|
||||
private static void betterVehicleHitboxes() {
|
||||
betterVehicleHitboxes = getBoolean("better-vehicle-hitboxes", true);
|
||||
@ -263,5 +289,4 @@ public class PaperSpigotConfig
|
||||
private static void kickChatMessageLength() {
|
||||
kickChatMessageLength = getBoolean("kick-chat-message-length", false);
|
||||
}
|
||||
// KigPaper end
|
||||
}
|
||||
|
@ -402,4 +402,14 @@ public class PaperSpigotWorldConfig
|
||||
{
|
||||
portalSearchRadius = getInt("portal-search-radius", 128);
|
||||
}
|
||||
|
||||
public boolean removeCorruptTEs;
|
||||
private void removeCorruptTEs() {
|
||||
removeCorruptTEs = getBoolean("remove-corrupt-tile-entities", false);
|
||||
}
|
||||
|
||||
public boolean armorStandEntityLookups;
|
||||
private void armorStandEntityLookups() {
|
||||
armorStandEntityLookups = getBoolean("armor-stands-do-collision-entity-lookups", true);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package org.github.paperspigot;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.craftbukkit.scheduler.CraftTask;
|
||||
import org.github.paperspigot.event.ServerExceptionEvent;
|
||||
import org.github.paperspigot.exception.ServerSchedulerException;
|
||||
|
||||
/**
|
||||
* Reporting wrapper to catch exceptions not natively
|
||||
*/
|
||||
public class ServerSchedulerReportingWrapper implements Runnable {
|
||||
|
||||
private final CraftTask internalTask;
|
||||
|
||||
public ServerSchedulerReportingWrapper(CraftTask internalTask) {
|
||||
this.internalTask = Preconditions.checkNotNull(internalTask, "internalTask");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
internalTask.run();
|
||||
} catch (RuntimeException e) {
|
||||
internalTask.getOwner().getServer().getPluginManager().callEvent(
|
||||
new ServerExceptionEvent(new ServerSchedulerException(e, internalTask))
|
||||
);
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
internalTask.getOwner().getServer().getPluginManager().callEvent(
|
||||
new ServerExceptionEvent(new ServerSchedulerException(t, internalTask))
|
||||
); //Do not rethrow, since it is not permitted with Runnable#run
|
||||
}
|
||||
}
|
||||
|
||||
public CraftTask getInternalTask() {
|
||||
return internalTask;
|
||||
}
|
||||
}
|
@ -126,9 +126,11 @@ public class ActivationRange
|
||||
{
|
||||
for ( int j1 = k; j1 <= l; ++j1 )
|
||||
{
|
||||
if ( world.getWorld().isChunkLoaded( i1, j1 ) )
|
||||
Chunk chunk = world.getChunkIfLoaded( i1, j1 ); // SportPaper - remove double chunk lookup
|
||||
|
||||
if ( chunk != null )
|
||||
{
|
||||
activateChunkEntities( world.getChunkAt( i1, j1 ) );
|
||||
activateChunkEntities( chunk );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class RestartCommand extends Command
|
||||
{
|
||||
if ( testPermission( sender ) )
|
||||
{
|
||||
MinecraftServer.getServer().processQueue.add(RestartCommand::restart);
|
||||
MinecraftServer.getServer().addMainThreadTask(RestartCommand::restart);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ public class WatchdogThread extends Thread
|
||||
while ( !stopping )
|
||||
{
|
||||
//
|
||||
if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime )
|
||||
if ( lastTick != 0 && System.currentTimeMillis() > lastTick + timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
|
||||
{
|
||||
Logger log = Bukkit.getServer().getLogger();
|
||||
log.log( Level.SEVERE, "The server has stopped responding!" );
|
||||
|
@ -3,10 +3,10 @@
|
||||
<Appenders>
|
||||
<Console name="WINDOWS_COMPAT" target="SYSTEM_OUT"></Console>
|
||||
<Queue name="TerminalConsole">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n" />
|
||||
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg{nolookups}%n" />
|
||||
</Queue>
|
||||
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
|
||||
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
|
||||
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n" />
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy />
|
||||
<OnStartupTriggeringPolicy />
|
||||
|
Loading…
Reference in New Issue
Block a user