More more more more patches
This commit is contained in:
parent
c321ca57db
commit
aac58bb772
42 changed files with 119 additions and 123 deletions
|
@ -1,46 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Thu, 28 Sep 2017 17:21:44 -0400
|
||||
Subject: [PATCH] Add PlayerJumpEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 72395ede1fe2570fb5bd463ddff191fc50b98191..b339a9b20f2d81a5f93bf2266d9896aae3886c3d 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1186,7 +1186,34 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||
boolean flag = d8 > 0.0D;
|
||||
|
||||
if (this.player.isOnGround() && !packet.isOnGround() && flag) {
|
||||
- this.player.jumpFromGround();
|
||||
+ // Paper start - Add player jump event
|
||||
+ Player player = this.getCraftPlayer();
|
||||
+ Location from = new Location(player.getWorld(), lastPosX, lastPosY, lastPosZ, lastYaw, lastPitch); // Get the Players previous Event location.
|
||||
+ Location to = player.getLocation().clone(); // Start off the To location as the Players current location.
|
||||
+
|
||||
+ // If the packet contains movement information then we update the To location with the correct XYZ.
|
||||
+ if (packet.hasPos) {
|
||||
+ to.setX(packet.x);
|
||||
+ to.setY(packet.y);
|
||||
+ to.setZ(packet.z);
|
||||
+ }
|
||||
+
|
||||
+ // If the packet contains look information then we update the To location with the correct Yaw & Pitch.
|
||||
+ if (packet.hasRot) {
|
||||
+ to.setYaw(packet.yRot);
|
||||
+ to.setPitch(packet.xRot);
|
||||
+ }
|
||||
+
|
||||
+ com.destroystokyo.paper.event.player.PlayerJumpEvent event = new com.destroystokyo.paper.event.player.PlayerJumpEvent(player, from, to);
|
||||
+
|
||||
+ if (event.callEvent()) {
|
||||
+ this.player.jumpFromGround();
|
||||
+ } else {
|
||||
+ from = event.getFrom();
|
||||
+ this.internalTeleport(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch(), Collections.emptySet(), false);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
boolean flag1 = this.player.verticalCollisionBelow;
|
|
@ -1,40 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Thu, 5 Oct 2017 01:54:07 +0100
|
||||
Subject: [PATCH] handle PacketPlayInKeepAlive async
|
||||
|
||||
In 1.12.2, Mojang moved the processing of PacketPlayInKeepAlive off the main
|
||||
thread, while entirely correct for the server, this causes issues with
|
||||
plugins which are expecting the PlayerQuitEvent on the main thread.
|
||||
|
||||
In order to counteract some bad behavior, we will post handling of the
|
||||
disconnection to the main thread, but leave the actual processing of the packet
|
||||
off the main thread.
|
||||
|
||||
also adding some additional logging in order to help work out what is causing
|
||||
random disconnections for clients.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index b339a9b20f2d81a5f93bf2266d9896aae3886c3d..a74b0cda6451e4368744e6d191bc5cf50eac3109 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2805,14 +2805,18 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||
|
||||
@Override
|
||||
public void handleKeepAlive(ServerboundKeepAlivePacket packet) {
|
||||
- PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel()); // CraftBukkit
|
||||
+ //PlayerConnectionUtils.ensureMainThread(packetplayinkeepalive, this, this.player.getWorldServer()); // CraftBukkit // Paper - This shouldn't be on the main thread
|
||||
if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) {
|
||||
int i = (int) (Util.getMillis() - this.keepAliveTime);
|
||||
|
||||
this.player.latency = (this.player.latency * 3 + i) / 4;
|
||||
this.keepAlivePending = false;
|
||||
} else if (!this.isSingleplayerOwner()) {
|
||||
+ // Paper start - This needs to be handled on the main thread for plugins
|
||||
+ server.submit(() -> {
|
||||
this.disconnect(new TranslatableComponent("disconnect.timeout"));
|
||||
+ });
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Minecrell <minecrell@minecrell.net>
|
||||
Date: Tue, 10 Oct 2017 18:45:20 +0200
|
||||
Subject: [PATCH] Expose client protocol version and virtual host
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java b/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..a5a7624f1f372a26b982836cd31cff15e2589e9b
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java
|
||||
@@ -0,0 +1,49 @@
|
||||
+package com.destroystokyo.paper.network;
|
||||
+
|
||||
+import java.net.InetSocketAddress;
|
||||
+
|
||||
+import javax.annotation.Nullable;
|
||||
+import net.minecraft.network.Connection;
|
||||
+
|
||||
+public class PaperNetworkClient implements NetworkClient {
|
||||
+
|
||||
+ private final Connection networkManager;
|
||||
+
|
||||
+ PaperNetworkClient(Connection networkManager) {
|
||||
+ this.networkManager = networkManager;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public InetSocketAddress getAddress() {
|
||||
+ return (InetSocketAddress) this.networkManager.getRemoteAddress();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getProtocolVersion() {
|
||||
+ return this.networkManager.protocolVersion;
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ @Override
|
||||
+ public InetSocketAddress getVirtualHost() {
|
||||
+ return this.networkManager.virtualHost;
|
||||
+ }
|
||||
+
|
||||
+ public static InetSocketAddress prepareVirtualHost(String host, int port) {
|
||||
+ int len = host.length();
|
||||
+
|
||||
+ // FML appends a marker to the host to recognize FML clients (\0FML\0)
|
||||
+ int pos = host.indexOf('\0');
|
||||
+ if (pos >= 0) {
|
||||
+ len = pos;
|
||||
+ }
|
||||
+
|
||||
+ // When clients connect with a SRV record, their host contains a trailing '.'
|
||||
+ if (len > 0 && host.charAt(len - 1) == '.') {
|
||||
+ len--;
|
||||
+ }
|
||||
+
|
||||
+ return InetSocketAddress.createUnresolved(host.substring(0, len), port);
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index dac5ab91fca602cdc2dbc308b24e15ce411659a2..1a2184e23f1e1b8e39141689ebc5f1d13d364038 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -93,6 +93,10 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
private float averageSentPackets;
|
||||
private int tickCount;
|
||||
private boolean handlingFault;
|
||||
+ // Paper start - NetworkClient implementation
|
||||
+ public int protocolVersion;
|
||||
+ public java.net.InetSocketAddress virtualHost;
|
||||
+ // Paper end
|
||||
|
||||
public Connection(PacketFlow side) {
|
||||
this.receiving = side;
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
index 63cc89c7769bfcc9d663a1827ad525e3ddd82fe5..a95b2ee0e80832f786bdb8f3d0bc00cbfae26fd4 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
|
||||
@@ -155,6 +155,10 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL
|
||||
throw new UnsupportedOperationException("Invalid intention " + packet.getIntention());
|
||||
}
|
||||
|
||||
+ // Paper start - NetworkClient implementation
|
||||
+ this.connection.protocolVersion = packet.getProtocolVersion();
|
||||
+ this.connection.virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(packet.hostName, packet.port);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index cebdc80d286a5daf1fdc9329dcff4f888890f91b..bb75dd9d6280f36f4ce03236558606c75026059e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -221,6 +221,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - Implement NetworkClient
|
||||
+ @Override
|
||||
+ public int getProtocolVersion() {
|
||||
+ if (getHandle().connection == null) return -1;
|
||||
+ return getHandle().connection.connection.protocolVersion;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public InetSocketAddress getVirtualHost() {
|
||||
+ if (getHandle().connection == null) return null;
|
||||
+ return getHandle().connection.connection.virtualHost;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public double getEyeHeight(boolean ignorePose) {
|
||||
if (ignorePose) {
|
|
@ -1,77 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 15 Oct 2017 00:29:07 +0100
|
||||
Subject: [PATCH] revert serverside behavior of keepalives
|
||||
|
||||
This patch intends to bump up the time that a client has to reply to the
|
||||
server back to 30 seconds as per pre 1.12.2, which allowed clients
|
||||
more than enough time to reply potentially allowing them to be less
|
||||
tempermental due to lag spikes on the network thread, e.g. that caused
|
||||
by plugins that are interacting with netty.
|
||||
|
||||
We also add a system property to allow people to tweak how long the server
|
||||
will wait for a reply. There is a compromise here between lower and higher
|
||||
values, lower values will mean that dead connections can be closed sooner,
|
||||
whereas higher values will make this less sensitive to issues such as spikes
|
||||
from networking or during connections flood of chunk packets on slower clients,
|
||||
at the cost of dead connections being kept open for longer.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index a74b0cda6451e4368744e6d191bc5cf50eac3109..e7f39bebc1ac4cbc5a0a7109c21d16d8126fd3cc 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -221,9 +221,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||
private final MinecraftServer server;
|
||||
public ServerPlayer player;
|
||||
private int tickCount;
|
||||
- private long keepAliveTime; @Deprecated private void setLastPing(long lastPing) { this.keepAliveTime = lastPing;}; @Deprecated private long getLastPing() { return this.keepAliveTime;}; // Paper - OBFHELPER
|
||||
- private boolean keepAlivePending; @Deprecated private void setPendingPing(boolean isPending) { this.keepAlivePending = isPending;}; @Deprecated private boolean isPendingPing() { return this.keepAlivePending;}; // Paper - OBFHELPER
|
||||
- private long keepAliveChallenge; @Deprecated private void setKeepAliveID(long keepAliveID) { this.keepAliveChallenge = keepAliveID;}; @Deprecated private long getKeepAliveID() {return this.keepAliveChallenge; }; // Paper - OBFHELPER
|
||||
+ private long keepAliveTime = Util.getMillis();
|
||||
+ private boolean keepAlivePending;
|
||||
+ private long keepAliveChallenge;
|
||||
// CraftBukkit start - multithreaded fields
|
||||
private final AtomicInteger chatSpamTickCount = new AtomicInteger();
|
||||
// CraftBukkit end
|
||||
@@ -252,6 +252,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||
private int aboveGroundVehicleTickCount;
|
||||
private int receivedMovePacketCount;
|
||||
private int knownMovePacketCount;
|
||||
+ private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit
|
||||
|
||||
public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player) {
|
||||
this.server = server;
|
||||
@@ -333,18 +334,25 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||
}
|
||||
|
||||
this.server.getProfiler().push("keepAlive");
|
||||
- long i = Util.getMillis();
|
||||
-
|
||||
- if (i - this.keepAliveTime >= 25000L) { // CraftBukkit
|
||||
- if (this.keepAlivePending) {
|
||||
- this.disconnect(new TranslatableComponent("disconnect.timeout"));
|
||||
- } else {
|
||||
+ // Paper Start - give clients a longer time to respond to pings as per pre 1.12.2 timings
|
||||
+ // This should effectively place the keepalive handling back to "as it was" before 1.12.2
|
||||
+ long currentTime = Util.getMillis();
|
||||
+ long elapsedTime = currentTime - this.keepAliveTime;
|
||||
+
|
||||
+ if (this.keepAlivePending) {
|
||||
+ if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected
|
||||
+ ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); // more info
|
||||
+ this.disconnect(new TranslatableComponent("disconnect.timeout", new Object[0]));
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (elapsedTime >= 15000L) { // 15 seconds
|
||||
this.keepAlivePending = true;
|
||||
- this.keepAliveTime = i;
|
||||
- this.keepAliveChallenge = i;
|
||||
+ this.keepAliveTime = currentTime;
|
||||
+ this.keepAliveChallenge = currentTime;
|
||||
this.send(new ClientboundKeepAlivePacket(this.keepAliveChallenge));
|
||||
}
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
this.server.getProfiler().pop();
|
||||
// CraftBukkit start
|
|
@ -1,80 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Brokkonaut <hannos17@gmx.de>
|
||||
Date: Tue, 31 Oct 2017 03:26:18 +0100
|
||||
Subject: [PATCH] Send attack SoundEffects only to players who can see the
|
||||
attacker
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
index 7fc4cd29bd487955886c81e6997d832a3185ec8e..de71d57b86d681efe0916dbee53be3ac826f9e2e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -31,6 +31,7 @@ import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket;
|
||||
+import net.minecraft.network.protocol.game.ClientboundSoundPacket;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
@@ -1201,7 +1202,7 @@ public abstract class Player extends LivingEntity {
|
||||
int i = b0 + EnchantmentHelper.getKnockbackBonus(this);
|
||||
|
||||
if (this.isSprinting() && flag) {
|
||||
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_KNOCKBACK, this.getSoundSource(), 1.0F, 1.0F);
|
||||
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_KNOCKBACK, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
|
||||
++i;
|
||||
flag1 = true;
|
||||
}
|
||||
@@ -1276,7 +1277,7 @@ public abstract class Player extends LivingEntity {
|
||||
}
|
||||
}
|
||||
|
||||
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_SWEEP, this.getSoundSource(), 1.0F, 1.0F);
|
||||
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_SWEEP, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
|
||||
this.sweepAttack();
|
||||
}
|
||||
|
||||
@@ -1304,15 +1305,15 @@ public abstract class Player extends LivingEntity {
|
||||
}
|
||||
|
||||
if (flag2) {
|
||||
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_CRIT, this.getSoundSource(), 1.0F, 1.0F);
|
||||
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_CRIT, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
|
||||
this.crit(target);
|
||||
}
|
||||
|
||||
if (!flag2 && !flag3) {
|
||||
if (flag) {
|
||||
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_STRONG, this.getSoundSource(), 1.0F, 1.0F);
|
||||
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_STRONG, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
|
||||
} else {
|
||||
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_WEAK, this.getSoundSource(), 1.0F, 1.0F);
|
||||
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_WEAK, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1364,7 +1365,7 @@ public abstract class Player extends LivingEntity {
|
||||
|
||||
this.causeFoodExhaustion(level.spigotConfig.combatExhaustion, EntityExhaustionEvent.ExhaustionReason.ATTACK); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value
|
||||
} else {
|
||||
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F);
|
||||
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
|
||||
if (flag4) {
|
||||
target.clearFire();
|
||||
}
|
||||
@@ -1811,6 +1812,14 @@ public abstract class Player extends LivingEntity {
|
||||
public int getXpNeededForNextLevel() {
|
||||
return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2);
|
||||
}
|
||||
+ // Paper start - send SoundEffect to everyone who can see fromEntity
|
||||
+ private static void sendSoundEffect(Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) {
|
||||
+ fromEntity.level.playSound(fromEntity, x, y, z, soundEffect, soundCategory, volume, pitch); // This will not send the effect to the entity himself
|
||||
+ if (fromEntity instanceof ServerPlayer) {
|
||||
+ ((ServerPlayer) fromEntity).connection.send(new ClientboundSoundPacket(soundEffect, soundCategory, x, y, z, volume, pitch));
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
// CraftBukkit start
|
||||
public void causeFoodExhaustion(float exhaustion) {
|
|
@ -1,31 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: pkt77 <parkerkt77@gmail.com>
|
||||
Date: Fri, 10 Nov 2017 23:46:34 -0500
|
||||
Subject: [PATCH] Add PlayerArmorChangeEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index a7e09145160f9c26b19a8d61564bf9c04e2616b1..2449cd753ec52b7e2d2213fcd3979d616a33c677 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraft.world.entity;
|
||||
|
||||
+import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent; // Paper
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -2941,6 +2942,13 @@ public abstract class LivingEntity extends Entity {
|
||||
ItemStack itemstack1 = this.getItemBySlot(enumitemslot);
|
||||
|
||||
if (!ItemStack.matches(itemstack1, itemstack)) {
|
||||
+ // Paper start - PlayerArmorChangeEvent
|
||||
+ if (this instanceof ServerPlayer && enumitemslot.getType() == EquipmentSlot.Type.ARMOR) {
|
||||
+ final org.bukkit.inventory.ItemStack oldItem = CraftItemStack.asBukkitCopy(itemstack);
|
||||
+ final org.bukkit.inventory.ItemStack newItem = CraftItemStack.asBukkitCopy(itemstack1);
|
||||
+ new PlayerArmorChangeEvent((Player) this.getBukkitEntity(), PlayerArmorChangeEvent.SlotType.valueOf(enumitemslot.name()), oldItem, newItem).callEvent();
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (map == null) {
|
||||
map = Maps.newEnumMap(EquipmentSlot.class);
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: killme <killme-git@ibts.me>
|
||||
Date: Sun, 12 Nov 2017 19:40:01 +0100
|
||||
Subject: [PATCH] Prevent logins from being processed when the player has
|
||||
disconnected
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 6834c67b38f0679497bef4b2174817d9688cbbd8..73efc3084b04914f7f06875651269fd584b60989 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -75,7 +75,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
|
||||
}
|
||||
// Paper end
|
||||
if (this.state == ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT) {
|
||||
- this.handleAcceptedLogin();
|
||||
+ // Paper start - prevent logins to be processed even though disconnect was called
|
||||
+ if (connection.isConnected()) {
|
||||
+ this.handleAcceptedLogin();
|
||||
+ }
|
||||
+ // Paper end
|
||||
} else if (this.state == ServerLoginPacketListenerImpl.State.DELAY_ACCEPT) {
|
||||
ServerPlayer entityplayer = this.server.getPlayerList().getPlayer(this.gameProfile.getId());
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: mezz <tehgeek@gmail.com>
|
||||
Date: Wed, 9 Aug 2017 17:51:22 -0500
|
||||
Subject: [PATCH] Fix MC-117075: TE Unload Lag Spike
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index d22b7edc9ddea765c11e82346afd3942e37831de..a7fbaa420bf18649cdcb94d53e7d5cfd704d9555 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -730,6 +730,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// Spigot start
|
||||
// Iterator iterator = this.blockEntityTickers.iterator();
|
||||
int tilesThisCycle = 0;
|
||||
+ var toRemove = new it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet<TickingBlockEntity>(net.minecraft.Util.identityStrategy()); // Paper - use removeAll
|
||||
+ toRemove.add(null);
|
||||
for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters
|
||||
this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0;
|
||||
TickingBlockEntity tickingblockentity = (TickingBlockEntity) this.blockEntityTickers.get(tileTickPosition);
|
||||
@@ -737,7 +739,6 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
if (tickingblockentity == null) {
|
||||
this.getCraftServer().getLogger().severe("Spigot has detected a null entity and has removed it, preventing a crash");
|
||||
tilesThisCycle--;
|
||||
- this.blockEntityTickers.remove(this.tileTickPosition--);
|
||||
continue;
|
||||
}
|
||||
// Spigot end
|
||||
@@ -745,12 +746,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
if (tickingblockentity.isRemoved()) {
|
||||
// Spigot start
|
||||
tilesThisCycle--;
|
||||
- this.blockEntityTickers.remove(this.tileTickPosition--);
|
||||
+ toRemove.add(tickingblockentity); // Paper - use removeAll
|
||||
// Spigot end
|
||||
} else if (this.shouldTickBlocksAt(ChunkPos.asLong(tickingblockentity.getPos()))) {
|
||||
tickingblockentity.tick();
|
||||
}
|
||||
}
|
||||
+ this.blockEntityTickers.removeAll(toRemove);
|
||||
|
||||
timings.tileEntityTick.stopTiming(); // Spigot
|
||||
this.tickingBlockEntities = false;
|
|
@ -1,60 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Thu, 16 Nov 2017 12:12:41 +0000
|
||||
Subject: [PATCH] use CB BlockState implementations for captured blocks
|
||||
|
||||
When modifying the world, CB will store a copy of the affected
|
||||
blocks in order to restore their state in the case that the event
|
||||
is cancelled. This change only modifies the collection of blocks
|
||||
in the world by normal means, e.g. not during tree population,
|
||||
as the potentially marginal overheads would serve no advantage.
|
||||
|
||||
CB was using a CraftBlockState for all blocks, which causes issues
|
||||
should any block that uses information beyond a data ID would suffer
|
||||
from missing information, e.g. Skulls.
|
||||
|
||||
By using CBs CraftBlock#getState(), we will maintain a proper copy of
|
||||
the blockstate that will be valid for restoration, as opposed to dropping
|
||||
information on restoration when the event is cancelled.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index a7fbaa420bf18649cdcb94d53e7d5cfd704d9555..46168d119d10231b8b946015245a476e0b56d567 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -142,7 +142,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public boolean preventPoiUpdated = false; // CraftBukkit - SPIGOT-5710
|
||||
public boolean captureBlockStates = false;
|
||||
public boolean captureTreeGeneration = false;
|
||||
- public Map<BlockPos, CapturedBlockState> capturedBlockStates = new java.util.LinkedHashMap<>();
|
||||
+ public Map<BlockPos, org.bukkit.craftbukkit.block.CraftBlockState> capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper
|
||||
public Map<BlockPos, BlockEntity> capturedTileEntities = new HashMap<>();
|
||||
public List<ItemEntity> captureDrops;
|
||||
public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<SpawnCategory> ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>();
|
||||
@@ -361,7 +361,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
|
||||
// CraftBukkit start - tree generation
|
||||
if (this.captureTreeGeneration) {
|
||||
- CapturedBlockState blockstate = this.capturedBlockStates.get(pos);
|
||||
+ CraftBlockState blockstate = this.capturedBlockStates.get(pos);
|
||||
if (blockstate == null) {
|
||||
blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags);
|
||||
this.capturedBlockStates.put(pos.immutable(), blockstate);
|
||||
@@ -381,7 +381,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
// CraftBukkit start - capture blockstates
|
||||
boolean captured = false;
|
||||
if (this.captureBlockStates && !this.capturedBlockStates.containsKey(pos)) {
|
||||
- CapturedBlockState blockstate = CapturedBlockState.getBlockState(this, pos, flags);
|
||||
+ CraftBlockState blockstate = (CraftBlockState) world.getBlockAt(pos.getX(), pos.getY(), pos.getZ()).getState(); // Paper - use CB getState to get a suitable snapshot
|
||||
+ blockstate.setFlag(flags); // Paper - set flag
|
||||
this.capturedBlockStates.put(pos.immutable(), blockstate);
|
||||
captured = true;
|
||||
}
|
||||
@@ -650,7 +651,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
// CraftBukkit start - tree generation
|
||||
if (this.captureTreeGeneration) {
|
||||
- CapturedBlockState previous = this.capturedBlockStates.get(pos);
|
||||
+ CraftBlockState previous = this.capturedBlockStates.get(pos); // Paper
|
||||
if (previous != null) {
|
||||
return previous.getHandle();
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 6 Nov 2017 21:08:22 -0500
|
||||
Subject: [PATCH] API to get a BlockState without a snapshot
|
||||
|
||||
This allows you to get a BlockState without creating a snapshot, operating
|
||||
on the real tile entity.
|
||||
|
||||
This is useful for where performance is needed
|
||||
|
||||
also Avoid NPE during CraftBlockEntityState load if could not get TE
|
||||
|
||||
If Tile Entity was null, correct Sign to return empty lines instead of null
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
index 148e79ae4e24fe16dbbb17550c3f258d4362c266..06beb18e5e1950aeb6cb427876fcc4c5ea95adb2 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -45,6 +45,7 @@ public abstract class BlockEntity {
|
||||
this.type = type;
|
||||
this.worldPosition = pos.immutable();
|
||||
this.blockState = state;
|
||||
+ this.persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY); // Paper - always init
|
||||
}
|
||||
|
||||
public static BlockPos getPosFromTag(CompoundTag nbt) {
|
||||
@@ -66,7 +67,7 @@ public abstract class BlockEntity {
|
||||
|
||||
// CraftBukkit start - read container
|
||||
public void load(CompoundTag nbt) {
|
||||
- this.persistentDataContainer = new CraftPersistentDataContainer(BlockEntity.DATA_TYPE_REGISTRY);
|
||||
+ this.persistentDataContainer.clear(); // Paper - clear instead of init
|
||||
|
||||
net.minecraft.nbt.Tag persistentDataTag = nbt.get("PublicBukkitValues");
|
||||
if (persistentDataTag instanceof CompoundTag) {
|
||||
@@ -240,8 +241,15 @@ public abstract class BlockEntity {
|
||||
|
||||
// CraftBukkit start - add method
|
||||
public InventoryHolder getOwner() {
|
||||
+ // Paper start
|
||||
+ return getOwner(true);
|
||||
+ }
|
||||
+ public InventoryHolder getOwner(boolean useSnapshot) {
|
||||
+ // Paper end
|
||||
if (this.level == null) return null;
|
||||
- org.bukkit.block.BlockState state = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ()).getState();
|
||||
+ org.bukkit.block.Block block = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ());
|
||||
+ if (block.getType() == org.bukkit.Material.AIR) return null;
|
||||
+ org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper
|
||||
if (state instanceof InventoryHolder) return (InventoryHolder) state;
|
||||
return null;
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
index 52fc42050d5df0882586c8f4bb4890ef1dbf979e..ba8f9ffed49bf377be8b37532d4f2bdcb8c44d82 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
@@ -329,6 +329,13 @@ public class CraftBlock implements Block {
|
||||
return CraftBlockStates.getBlockState(this);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public BlockState getState(boolean useSnapshot) {
|
||||
+ return CraftBlockStates.getBlockState(this, useSnapshot);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Biome getBiome() {
|
||||
return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ());
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
index 7629a51ec284cab0db7e9238027d6acfa4f3083c..a76cce199acdcecfdd8b998ec08974c2ed0751cf 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
@@ -10,15 +10,26 @@ public class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockStat
|
||||
|
||||
private final T tileEntity;
|
||||
private final T snapshot;
|
||||
+ public final boolean snapshotDisabled; // Paper
|
||||
+ public static boolean DISABLE_SNAPSHOT = false; // Paper
|
||||
|
||||
public CraftBlockEntityState(World world, T tileEntity) {
|
||||
super(world, tileEntity.getBlockPos(), tileEntity.getBlockState());
|
||||
|
||||
this.tileEntity = tileEntity;
|
||||
|
||||
+ // Paper start
|
||||
+ this.snapshotDisabled = DISABLE_SNAPSHOT;
|
||||
+ if (DISABLE_SNAPSHOT) {
|
||||
+ this.snapshot = this.tileEntity;
|
||||
+ } else {
|
||||
+ this.snapshot = this.createSnapshot(tileEntity);
|
||||
+ }
|
||||
// copy tile entity data:
|
||||
- this.snapshot = this.createSnapshot(tileEntity);
|
||||
- this.load(snapshot);
|
||||
+ if (this.snapshot != null) {
|
||||
+ this.load(this.snapshot);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public void refreshSnapshot() {
|
||||
@@ -105,4 +116,11 @@ public class CraftBlockEntityState<T extends BlockEntity> extends CraftBlockStat
|
||||
public PersistentDataContainer getPersistentDataContainer() {
|
||||
return this.getSnapshot().persistentDataContainer;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isSnapshot() {
|
||||
+ return !this.snapshotDisabled;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
index 51ea68c433c4d530f8404d3174c5a121ce808a96..93a8aeb5545c794ac425c35f8af52a443cd060ca 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
@@ -324,15 +324,30 @@ public final class CraftBlockStates {
|
||||
}
|
||||
|
||||
public static BlockState getBlockState(Block block) {
|
||||
+ // Paper start
|
||||
+ return CraftBlockStates.getBlockState(block, true);
|
||||
+ }
|
||||
+ public static BlockState getBlockState(Block block, boolean useSnapshot) {
|
||||
+ // Paper end
|
||||
Preconditions.checkNotNull(block, "block is null");
|
||||
CraftBlock craftBlock = (CraftBlock) block;
|
||||
CraftWorld world = (CraftWorld) block.getWorld();
|
||||
BlockPos blockPosition = craftBlock.getPosition();
|
||||
net.minecraft.world.level.block.state.BlockState blockData = craftBlock.getNMS();
|
||||
BlockEntity tileEntity = craftBlock.getHandle().getBlockEntity(blockPosition);
|
||||
+ // Paper start - block state snapshots
|
||||
+ boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT;
|
||||
+ CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot;
|
||||
+ try {
|
||||
+ // Paper end
|
||||
CraftBlockState blockState = CraftBlockStates.getBlockState(world, blockPosition, blockData, tileEntity);
|
||||
blockState.setWorldHandle(craftBlock.getHandle()); // Inject the block's generator access
|
||||
return blockState;
|
||||
+ // Paper start
|
||||
+ } finally {
|
||||
+ CraftBlockEntityState.DISABLE_SNAPSHOT = prev;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public static BlockState getBlockState(Material material, @Nullable CompoundTag blockEntityTag) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
|
||||
index 3fc3907172f12ee24ea70bd6a1ffbbc6084ed971..2c59f09a9261a1690951161fd856a5848d9885b7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
|
||||
@@ -156,4 +156,10 @@ public class CraftPersistentDataContainer implements PersistentDataContainer {
|
||||
public Map<String, Object> serialize() {
|
||||
return (Map<String, Object>) CraftNBTTagConfigSerializer.serialize(this.toTagCompound());
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ public void clear() {
|
||||
+ this.customDataTags.clear();
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 26 Nov 2017 13:19:58 -0500
|
||||
Subject: [PATCH] AsyncTabCompleteEvent
|
||||
|
||||
Let plugins be able to control tab completion of commands and chat async.
|
||||
|
||||
This will be useful for frameworks like ACF so we can define async safe completion handlers,
|
||||
and avoid going to main for tab completions.
|
||||
|
||||
Especially useful if you need to query a database in order to obtain the results for tab
|
||||
completion, such as offline players.
|
||||
|
||||
Also adds isCommand and getLocation to the sync TabCompleteEvent
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index e7f39bebc1ac4cbc5a0a7109c21d16d8126fd3cc..ee482d8942a355d989a2c913c23245bdbfb866a1 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -708,10 +708,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||
|
||||
@Override
|
||||
public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) {
|
||||
- PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
|
||||
+ // PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.getWorldServer()); // Paper - run this async
|
||||
// CraftBukkit start
|
||||
if (this.chatSpamTickCount.addAndGet(1) > 500 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) {
|
||||
- this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]));
|
||||
+ server.scheduleOnMain(() -> this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]))); // Paper
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@@ -721,12 +721,35 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||
stringreader.skip();
|
||||
}
|
||||
|
||||
- ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
|
||||
+ // Paper start - async tab completion
|
||||
+ com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event;
|
||||
+ java.util.List<String> completions = new java.util.ArrayList<>();
|
||||
+ String buffer = packet.getCommand();
|
||||
+ event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getCraftPlayer(), completions,
|
||||
+ buffer, true, null);
|
||||
+ event.callEvent();
|
||||
+ completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.getCompletions();
|
||||
+ // If the event isn't handled, we can assume that we have no completions, and so we'll ask the server
|
||||
+ if (!event.isHandled()) {
|
||||
+ if (!event.isCancelled()) {
|
||||
+
|
||||
+ this.server.scheduleOnMain(() -> { // Paper - This needs to be on main
|
||||
+ ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
|
||||
|
||||
- this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
|
||||
- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer
|
||||
- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions));
|
||||
- });
|
||||
+ this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
|
||||
+ if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer
|
||||
+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions));
|
||||
+ });
|
||||
+ });
|
||||
+ }
|
||||
+ } else if (!completions.isEmpty()) {
|
||||
+ com.mojang.brigadier.suggestion.SuggestionsBuilder builder = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packet.getCommand(), stringreader.getTotalLength());
|
||||
+
|
||||
+ builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1);
|
||||
+ completions.forEach(builder::suggest);
|
||||
+ player.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join()));
|
||||
+ }
|
||||
+ // Paper end - async tab completion
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index c091aa6cbb541ce5349ffb183bc7d67b0c4fafeb..77c5180d36f09cfeb7a82c6e321793ac1a363a48 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2078,7 +2078,7 @@ public final class CraftServer implements Server {
|
||||
offers = this.tabCompleteChat(player, message);
|
||||
}
|
||||
|
||||
- TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers);
|
||||
+ TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers, message.startsWith("/") || forceCommand, pos != null ? net.minecraft.server.MCUtil.toLocation(((CraftWorld) player.getWorld()).getHandle(), new BlockPos(pos)) : null); // Paper
|
||||
this.getPluginManager().callEvent(tabEvent);
|
||||
|
||||
return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
||||
index b996fde481cebbbcce80a6c267591136db7cc0bc..e5af155d75f717d33c23e22ff8b96bb3ff87844d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
|
||||
@@ -28,6 +28,39 @@ public class ConsoleCommandCompleter implements Completer {
|
||||
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
||||
final CraftServer server = this.server.server;
|
||||
final String buffer = line.line();
|
||||
+ // Async Tab Complete
|
||||
+ com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event;
|
||||
+ java.util.List<String> completions = new java.util.ArrayList<>();
|
||||
+ event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(server.getConsoleSender(), completions,
|
||||
+ buffer, true, null);
|
||||
+ event.callEvent();
|
||||
+ completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.getCompletions();
|
||||
+
|
||||
+ if (event.isCancelled() || event.isHandled()) {
|
||||
+ // Still fire sync event with the provided completions, if someone is listening
|
||||
+ if (!event.isCancelled() && TabCompleteEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
+ List<String> finalCompletions = completions;
|
||||
+ Waitable<List<String>> syncCompletions = new Waitable<List<String>>() {
|
||||
+ @Override
|
||||
+ protected List<String> evaluate() {
|
||||
+ org.bukkit.event.server.TabCompleteEvent syncEvent = new org.bukkit.event.server.TabCompleteEvent(server.getConsoleSender(), buffer, finalCompletions);
|
||||
+ return syncEvent.callEvent() ? syncEvent.getCompletions() : com.google.common.collect.ImmutableList.of();
|
||||
+ }
|
||||
+ };
|
||||
+ server.getServer().processQueue.add(syncCompletions);
|
||||
+ try {
|
||||
+ completions = syncCompletions.get();
|
||||
+ } catch (InterruptedException | ExecutionException e1) {
|
||||
+ e1.printStackTrace();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!completions.isEmpty()) {
|
||||
+ candidates.addAll(completions.stream().map(Candidate::new).collect(java.util.stream.Collectors.toList()));
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// Paper end
|
||||
Waitable<List<String>> waitable = new Waitable<List<String>>() {
|
||||
@Override
|
|
@ -1,20 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 19 Dec 2017 22:02:53 -0500
|
||||
Subject: [PATCH] PlayerPickupExperienceEvent
|
||||
|
||||
Allows plugins to cancel a player picking up an experience orb
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
index 227aca795efc99c4f81dfb30c00d31d2d7524542..6bf6d6629dfb9338d3e34f433a5698904a2acdad 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
@@ -301,7 +301,7 @@ public class ExperienceOrb extends Entity {
|
||||
@Override
|
||||
public void playerTouch(Player player) {
|
||||
if (!this.level.isClientSide) {
|
||||
- if (player.takeXpDelay == 0) {
|
||||
+ if (player.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper
|
||||
player.takeXpDelay = 2;
|
||||
player.take(this, 1);
|
||||
int i = this.repairPlayerItems(player, this.value);
|
|
@ -1,54 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 20 Dec 2017 17:36:49 -0500
|
||||
Subject: [PATCH] Ability to apply mending to XP API
|
||||
|
||||
This allows plugins that give players the ability to apply the experience
|
||||
points to the Item Mending formula, which will repair an item instead
|
||||
of giving the player experience points.
|
||||
|
||||
Both an API To standalone mend, and apply mending logic to .giveExp has been added.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index bb75dd9d6280f36f4ce03236558606c75026059e..19e8ec4baf0967693121b2e3443d436f85f518ec 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -1349,7 +1349,37 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
|
||||
@Override
|
||||
- public void giveExp(int exp) {
|
||||
+ // Paper start
|
||||
+ public int applyMending(int amount) {
|
||||
+ ServerPlayer handle = this.getHandle();
|
||||
+ // Logic copied from EntityExperienceOrb and remapped to unobfuscated methods/properties
|
||||
+ final var stackEntry = net.minecraft.world.item.enchantment.EnchantmentHelper
|
||||
+ .getRandomItemWith(net.minecraft.world.item.enchantment.Enchantments.MENDING, handle);
|
||||
+ final net.minecraft.world.item.ItemStack itemstack = stackEntry != null ? stackEntry.getValue() : net.minecraft.world.item.ItemStack.EMPTY;
|
||||
+ if (!itemstack.isEmpty() && itemstack.getItem().canBeDepleted()) {
|
||||
+ net.minecraft.world.entity.ExperienceOrb orb = net.minecraft.world.entity.EntityType.EXPERIENCE_ORB.create(handle.level);
|
||||
+ orb.value = amount;
|
||||
+ orb.spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM;
|
||||
+ orb.setPosRaw(handle.getX(), handle.getY(), handle.getZ());
|
||||
+
|
||||
+ int i = Math.min(orb.xpToDurability(amount), itemstack.getDamageValue());
|
||||
+ org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, i);
|
||||
+ i = event.getRepairAmount();
|
||||
+ orb.discard();
|
||||
+ if (!event.isCancelled()) {
|
||||
+ amount -= orb.durabilityToXp(i);
|
||||
+ itemstack.setDamageValue(itemstack.getDamageValue() - i);
|
||||
+ }
|
||||
+ }
|
||||
+ return amount;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void giveExp(int exp, boolean applyMending) {
|
||||
+ if (applyMending) {
|
||||
+ exp = this.applyMending(exp);
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.getHandle().giveExperiencePoints(exp);
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 14 Jan 2018 17:36:02 -0500
|
||||
Subject: [PATCH] PlayerNaturallySpawnCreaturesEvent
|
||||
|
||||
This event can be used for when you want to exclude a certain player
|
||||
from triggering monster spawns on a server.
|
||||
|
||||
Also a highly more effecient way to blanket block spawns in a world
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
index f5cf71258732aa040443eb82e09ab28f130e4c79..81eb73e9fde37e3b196bd899ecd4d614897d1a98 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1114,7 +1114,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
||||
chunkRange = (chunkRange > 8) ? 8 : chunkRange;
|
||||
|
||||
- double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D;
|
||||
+ final int finalChunkRange = chunkRange; // Paper for lambda below
|
||||
+ //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event
|
||||
+ double blockRange = 16384.0D; // Paper
|
||||
// Spigot end
|
||||
long i = chunkcoordintpair.toLong();
|
||||
|
||||
@@ -1131,6 +1133,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
entityplayer = (ServerPlayer) iterator.next();
|
||||
+ // Paper start - add PlayerNaturallySpawnCreaturesEvent
|
||||
+ com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
|
||||
+ blockRange = 16384.0D;
|
||||
+ if (reducedRange) {
|
||||
+ event = entityplayer.playerNaturallySpawnedEvent;
|
||||
+ if (event == null || event.isCancelled()) return false;
|
||||
+ blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4));
|
||||
+ }
|
||||
+ // Paper end
|
||||
} while (!this.playerIsCloseEnoughForSpawning(entityplayer, chunkcoordintpair, blockRange)); // Spigot
|
||||
|
||||
return true;
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index d198303d4d0cff34156c00176ec2f3f2ad42ada4..f2d92cd125cbc1bd6fdab774e7002d6b7eda29fc 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -818,6 +818,15 @@ public class ServerChunkCache extends ChunkSource {
|
||||
boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
||||
|
||||
Collections.shuffle(list);
|
||||
+ // Paper start - call player naturally spawn event
|
||||
+ int chunkRange = level.spigotConfig.mobSpawnRange;
|
||||
+ chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
|
||||
+ chunkRange = Math.min(chunkRange, 8);
|
||||
+ for (ServerPlayer entityPlayer : this.level.players()) {
|
||||
+ entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange);
|
||||
+ entityPlayer.playerNaturallySpawnedEvent.callEvent();
|
||||
+ };
|
||||
+ // Paper end
|
||||
Iterator iterator1 = list.iterator();
|
||||
|
||||
while (iterator1.hasNext()) {
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index eaa968b6d91160947235fad29d3b955b3ee149f3..3c780c0679ba004577393b3d801ee18ac7e847b9 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.minecraft.server.level;
|
||||
|
||||
+import com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
@@ -236,6 +237,7 @@ public class ServerPlayer extends Player {
|
||||
public Integer clientViewDistance;
|
||||
public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent
|
||||
// CraftBukkit end
|
||||
+ public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
|
||||
|
||||
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 14 Jan 2018 17:01:31 -0500
|
||||
Subject: [PATCH] PreCreatureSpawnEvent
|
||||
|
||||
Adds an event to fire before an Entity is created, so that plugins that need to cancel
|
||||
CreatureSpawnEvent can do so from this event instead.
|
||||
|
||||
Cancelling CreatureSpawnEvent rapidly causes a lot of garbage collection and CPU waste
|
||||
as it's done after the Entity object has been fully created.
|
||||
|
||||
Mob Limiting plugins and blanket "ban this type of monster" plugins should use this event
|
||||
instead and save a lot of server resources.
|
||||
|
||||
See: https://github.com/PaperMC/Paper/issues/917
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||
index 8699a3bd63e2df83615ae39a6873d9874f0fb8da..05a3d736193775c1aa6ce3759e13a1f76f747d09 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||
@@ -338,6 +338,20 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T> {
|
||||
|
||||
@Nullable
|
||||
public T spawn(ServerLevel worldserver, @Nullable CompoundTag nbttagcompound, @Nullable Component ichatbasecomponent, @Nullable Player entityhuman, BlockPos blockposition, MobSpawnType enummobspawn, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
|
||||
+ // Paper start - Call PreCreatureSpawnEvent
|
||||
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(EntityType.getKey(this).getPath());
|
||||
+ if (type != null) {
|
||||
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
|
||||
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||
+ net.minecraft.server.MCUtil.toLocation(worldserver, blockposition),
|
||||
+ type,
|
||||
+ spawnReason
|
||||
+ );
|
||||
+ if (!event.callEvent()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
T t0 = this.create(worldserver, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1);
|
||||
|
||||
if (t0 != null) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
index ac44ba98d0acc9aa2a75088d8a9a145fdbcbd911..ecd7083b40ce6230d49ea4487766a6f06b4e96d0 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
@@ -997,6 +997,21 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
BlockPos blockposition1 = this.findSpawnPositionForGolemInColumn(blockposition, d0, d1);
|
||||
|
||||
if (blockposition1 != null) {
|
||||
+ // Paper start - Call PreCreatureSpawnEvent
|
||||
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
|
||||
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||
+ net.minecraft.server.MCUtil.toLocation(level, blockposition1),
|
||||
+ org.bukkit.entity.EntityType.IRON_GOLEM,
|
||||
+ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE
|
||||
+ );
|
||||
+ if (!event.callEvent()) {
|
||||
+ if (event.shouldAbortSpawn()) {
|
||||
+ GolemSensor.golemDetected(this); // Set Golem Last Seen to stop it from spawning another one
|
||||
+ return null;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ // Paper end
|
||||
IronGolem entityirongolem = (IronGolem) EntityType.IRON_GOLEM.create(world, (CompoundTag) null, (Component) null, (Player) null, blockposition1, MobSpawnType.MOB_SUMMONED, false, false);
|
||||
|
||||
if (entityirongolem != null) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
index 5bf68b03ddfc7c9554c467e2c0588084a796f6fa..18b1b7c05665ee1fb06670ceded719b19f3a4ee3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
|
||||
@@ -122,6 +122,27 @@ public abstract class BaseSpawner {
|
||||
} else if (!SpawnPlacements.checkSpawnRules((EntityType) optional.get(), world, MobSpawnType.SPAWNER, blockposition1, world.getRandom())) {
|
||||
continue;
|
||||
}
|
||||
+ // Paper start
|
||||
+ EntityType<?> entityType = optional.get();
|
||||
+ String key = EntityType.getKey(entityType).getPath();
|
||||
+
|
||||
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(key);
|
||||
+ if (type != null) {
|
||||
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
|
||||
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||
+ net.minecraft.server.MCUtil.toLocation(world, d0, d1, d2),
|
||||
+ type,
|
||||
+ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER
|
||||
+ );
|
||||
+ if (!event.callEvent()) {
|
||||
+ flag = true;
|
||||
+ if (event.shouldAbortSpawn()) {
|
||||
+ break;
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
Entity entity = EntityType.loadEntityRecursive(nbttagcompound, world, (entity1) -> {
|
||||
entity1.moveTo(d0, d1, d2, entity1.getYRot(), entity1.getXRot());
|
||||
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
index fee21a585b95448a5edab70002e9c4ea36a5d989..a62c5f48e54d10eb416111448cd250704ef594a0 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -211,7 +211,13 @@ public final class NaturalSpawner {
|
||||
j1 = biomesettingsmobs_c.minCount + world.random.nextInt(1 + biomesettingsmobs_c.maxCount - biomesettingsmobs_c.minCount);
|
||||
}
|
||||
|
||||
- if (NaturalSpawner.isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2) && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) {
|
||||
+ // Paper start
|
||||
+ Boolean doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);
|
||||
+ if (doSpawning == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (doSpawning && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) {
|
||||
+ // Paper end
|
||||
Mob entityinsentient = NaturalSpawner.getMobForSpawn(world, biomesettingsmobs_c.type);
|
||||
|
||||
if (entityinsentient == null) {
|
||||
@@ -258,9 +264,25 @@ public final class NaturalSpawner {
|
||||
return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerToCenterThan(new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isNaturalSpawningAllowed((BlockPos) pos));
|
||||
}
|
||||
|
||||
- private static boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) {
|
||||
+ private static Boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { // Paper
|
||||
EntityType<?> entitytypes = spawnEntry.type;
|
||||
|
||||
+ // Paper start
|
||||
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
|
||||
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(EntityType.getKey(entitytypes).getPath());
|
||||
+ if (type != null) {
|
||||
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
|
||||
+ net.minecraft.server.MCUtil.toLocation(world, pos),
|
||||
+ type, SpawnReason.NATURAL
|
||||
+ );
|
||||
+ if (!event.callEvent()) {
|
||||
+ if (event.shouldAbortSpawn()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (entitytypes.getCategory() == MobCategory.MISC) {
|
||||
return false;
|
||||
} else if (!entitytypes.canSpawnFarFromPlayer() && squaredDistance > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance())) {
|
|
@ -1,104 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 19 Jan 2018 00:36:25 -0500
|
||||
Subject: [PATCH] Add setPlayerProfile API for Skulls
|
||||
|
||||
This allows you to create already filled textures on Skulls to avoid texture lookups
|
||||
which commonly cause rate limit issues with Mojang API
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java
|
||||
index 6ac03706a584e4cb07300cf6e34969a8c4595c58..0be71d9d06f34e9ac58da3bbef954b2786cee53b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java
|
||||
@@ -102,7 +102,22 @@ public class CraftSkull extends CraftBlockEntityState<SkullBlockEntity> implemen
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
@Override
|
||||
+ public void setPlayerProfile(com.destroystokyo.paper.profile.PlayerProfile profile) {
|
||||
+ Preconditions.checkNotNull(profile, "profile");
|
||||
+ this.profile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
|
||||
+ }
|
||||
+
|
||||
+ @javax.annotation.Nullable
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() {
|
||||
+ return profile != null ? com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitCopy(profile) : null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
+ @Override
|
||||
+ @Deprecated // Paper
|
||||
public PlayerProfile getOwnerProfile() {
|
||||
if (!this.hasOwner()) {
|
||||
return null;
|
||||
@@ -112,11 +127,12 @@ public class CraftSkull extends CraftBlockEntityState<SkullBlockEntity> implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
+ @Deprecated // Paper
|
||||
public void setOwnerProfile(PlayerProfile profile) {
|
||||
if (profile == null) {
|
||||
this.profile = null;
|
||||
} else {
|
||||
- this.profile = CraftPlayerProfile.validateSkullProfile(((CraftPlayerProfile) profile).buildGameProfile());
|
||||
+ this.profile = CraftPlayerProfile.validateSkullProfile(((com.destroystokyo.paper.profile.SharedPlayerProfile) profile).buildGameProfile()); // Paper
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
|
||||
index 545074f5f7b109daf17af05fa36a9dc5816f22d4..292ae4a68093b7d939a755e1062cee57da186ab1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
|
||||
@@ -143,6 +143,19 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
|
||||
return this.hasOwner() ? this.profile.getName() : null;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public void setPlayerProfile(@org.jetbrains.annotations.Nullable com.destroystokyo.paper.profile.PlayerProfile profile) {
|
||||
+ setProfile((profile == null) ? null : com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile));
|
||||
+ }
|
||||
+
|
||||
+ @org.jetbrains.annotations.Nullable
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() {
|
||||
+ return profile != null ? com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitCopy(profile) : null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public OfflinePlayer getOwningPlayer() {
|
||||
if (this.hasOwner()) {
|
||||
@@ -193,6 +206,7 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
|
||||
}
|
||||
|
||||
@Override
|
||||
+ @Deprecated // Paper
|
||||
public PlayerProfile getOwnerProfile() {
|
||||
if (!this.hasOwner()) {
|
||||
return null;
|
||||
@@ -202,11 +216,12 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
|
||||
}
|
||||
|
||||
@Override
|
||||
+ @Deprecated // Paper
|
||||
public void setOwnerProfile(PlayerProfile profile) {
|
||||
if (profile == null) {
|
||||
this.setProfile(null);
|
||||
} else {
|
||||
- this.setProfile(CraftPlayerProfile.validateSkullProfile(((CraftPlayerProfile) profile).buildGameProfile()));
|
||||
+ this.setProfile(CraftPlayerProfile.validateSkullProfile(((com.destroystokyo.paper.profile.SharedPlayerProfile) profile).buildGameProfile())); // Paper
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +258,7 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
|
||||
Builder<String, Object> serialize(Builder<String, Object> builder) {
|
||||
super.serialize(builder);
|
||||
if (this.profile != null) {
|
||||
- return builder.put(SKULL_OWNER.BUKKIT, new CraftPlayerProfile(this.profile));
|
||||
+ return builder.put(SKULL_OWNER.BUKKIT, new com.destroystokyo.paper.profile.CraftPlayerProfile(this.profile)); // Paper
|
||||
}
|
||||
return builder;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 2 Jan 2018 00:31:26 -0500
|
||||
Subject: [PATCH] Fill Profile Property Events
|
||||
|
||||
Allows plugins to populate profile properties from local sources to avoid calls out to Mojang API
|
||||
to fill in textures for example.
|
||||
|
||||
If Mojang API does need to be hit, event fire so you can get the results.
|
||||
|
||||
This is useful for implementing a ProfileCache for Player Skulls
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java b/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java
|
||||
index 93d73c27340645c7502acafdc0b2cfbc1a759dd8..5c7d2ee19243d0911a3a00af3ae42078a2ccba94 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.destroystokyo.paper.profile;
|
||||
|
||||
import com.mojang.authlib.Environment;
|
||||
+import com.destroystokyo.paper.event.profile.FillProfileEvent;
|
||||
+import com.destroystokyo.paper.event.profile.PreFillProfileEvent;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
|
||||
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
|
||||
@@ -20,7 +22,15 @@ public class PaperMinecraftSessionService extends YggdrasilMinecraftSessionServi
|
||||
|
||||
@Override
|
||||
public GameProfile fillProfileProperties(GameProfile profile, boolean requireSecure) {
|
||||
- return super.fillProfileProperties(profile, requireSecure);
|
||||
+ CraftPlayerProfile playerProfile = (CraftPlayerProfile) CraftPlayerProfile.asBukkitMirror(profile);
|
||||
+ new PreFillProfileEvent(playerProfile).callEvent();
|
||||
+ profile = playerProfile.getGameProfile();
|
||||
+ if (profile.isComplete() && profile.getProperties().containsKey("textures")) {
|
||||
+ return profile;
|
||||
+ }
|
||||
+ GameProfile gameProfile = super.fillProfileProperties(profile, requireSecure);
|
||||
+ new FillProfileEvent(CraftPlayerProfile.asBukkitMirror(gameProfile)).callEvent();
|
||||
+ return gameProfile;
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,23 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 19 Jan 2018 08:15:29 -0600
|
||||
Subject: [PATCH] PlayerAdvancementCriterionGrantEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
index e5ffc18cbd107b9fd20a9781f6f1979e9598378f..ecd62d2625bc5def3ac68f642f2c6f156060f129 100644
|
||||
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
@@ -277,6 +277,12 @@ public class PlayerAdvancements {
|
||||
boolean flag1 = advancementprogress.isDone();
|
||||
|
||||
if (advancementprogress.grantProgress(criterionName)) {
|
||||
+ // Paper start
|
||||
+ if (!new com.destroystokyo.paper.event.player.PlayerAdvancementCriterionGrantEvent(this.player.getBukkitEntity(), advancement.bukkit, criterionName).callEvent()) {
|
||||
+ advancementprogress.revokeProgress(criterionName);
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.unregisterListeners(advancement);
|
||||
this.progressChanged.add(advancement);
|
||||
flag = true;
|
|
@ -1,287 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Sat, 27 Jan 2018 17:04:14 -0500
|
||||
Subject: [PATCH] Add ArmorStand Item Meta
|
||||
|
||||
This is adds basic item meta for armor stands. It does not add all
|
||||
possible metadata however.
|
||||
|
||||
There are armor, hand, and equipment types, as well as position data
|
||||
that can also be added here. This initial addition should serve a
|
||||
starting point for future additions in this area.
|
||||
|
||||
Fixes GH-559
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java
|
||||
index 1b8be8a7103e09065a405a22d427b9a747fc1a3e..2afedf24e485dd36e95988843c70af880d679b1f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java
|
||||
@@ -9,9 +9,22 @@ import org.bukkit.configuration.serialization.DelegateDeserialization;
|
||||
import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey;
|
||||
|
||||
@DelegateDeserialization(CraftMetaItem.SerializableMeta.class)
|
||||
-public class CraftMetaArmorStand extends CraftMetaItem {
|
||||
+public class CraftMetaArmorStand extends CraftMetaItem implements com.destroystokyo.paper.inventory.meta.ArmorStandMeta { // Paper
|
||||
|
||||
static final ItemMetaKey ENTITY_TAG = new ItemMetaKey("EntityTag", "entity-tag");
|
||||
+ // Paper start
|
||||
+ static final ItemMetaKey INVISIBLE = new ItemMetaKey("Invisible", "invisible");
|
||||
+ static final ItemMetaKey NO_BASE_PLATE = new ItemMetaKey("NoBasePlate", "no-base-plate");
|
||||
+ static final ItemMetaKey SHOW_ARMS = new ItemMetaKey("ShowArms", "show-arms");
|
||||
+ static final ItemMetaKey SMALL = new ItemMetaKey("Small", "small");
|
||||
+ static final ItemMetaKey MARKER = new ItemMetaKey("Marker", "marker");
|
||||
+
|
||||
+ private boolean invisible;
|
||||
+ private boolean noBasePlate;
|
||||
+ private boolean showArms;
|
||||
+ private boolean small;
|
||||
+ private boolean marker;
|
||||
+ // Paper end
|
||||
CompoundTag entityTag;
|
||||
|
||||
CraftMetaArmorStand(CraftMetaItem meta) {
|
||||
@@ -22,6 +35,13 @@ public class CraftMetaArmorStand extends CraftMetaItem {
|
||||
}
|
||||
|
||||
CraftMetaArmorStand armorStand = (CraftMetaArmorStand) meta;
|
||||
+ // Paper start
|
||||
+ this.invisible = armorStand.invisible;
|
||||
+ this.noBasePlate = armorStand.noBasePlate;
|
||||
+ this.showArms = armorStand.showArms;
|
||||
+ this.small = armorStand.small;
|
||||
+ this.marker = armorStand.marker;
|
||||
+ // Paper end
|
||||
this.entityTag = armorStand.entityTag;
|
||||
}
|
||||
|
||||
@@ -30,11 +50,39 @@ public class CraftMetaArmorStand extends CraftMetaItem {
|
||||
|
||||
if (tag.contains(ENTITY_TAG.NBT)) {
|
||||
this.entityTag = tag.getCompound(ENTITY_TAG.NBT).copy();
|
||||
+ // Paper start
|
||||
+ if (entityTag.contains(INVISIBLE.NBT)) {
|
||||
+ invisible = entityTag.getBoolean(INVISIBLE.NBT);
|
||||
+ }
|
||||
+
|
||||
+ if (entityTag.contains(NO_BASE_PLATE.NBT)) {
|
||||
+ noBasePlate = entityTag.getBoolean(NO_BASE_PLATE.NBT);
|
||||
+ }
|
||||
+
|
||||
+ if (entityTag.contains(SHOW_ARMS.NBT)) {
|
||||
+ showArms = entityTag.getBoolean(SHOW_ARMS.NBT);
|
||||
+ }
|
||||
+
|
||||
+ if (entityTag.contains(SMALL.NBT)) {
|
||||
+ small = entityTag.getBoolean(SMALL.NBT);
|
||||
+ }
|
||||
+
|
||||
+ if (entityTag.contains(MARKER.NBT)) {
|
||||
+ marker = entityTag.getBoolean(MARKER.NBT);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
CraftMetaArmorStand(Map<String, Object> map) {
|
||||
super(map);
|
||||
+ // Paper start
|
||||
+ this.invisible = SerializableMeta.getBoolean(map, INVISIBLE.BUKKIT);
|
||||
+ this.noBasePlate = SerializableMeta.getBoolean(map, NO_BASE_PLATE.BUKKIT);
|
||||
+ this.showArms = SerializableMeta.getBoolean(map, SHOW_ARMS.BUKKIT);
|
||||
+ this.small = SerializableMeta.getBoolean(map, SMALL.BUKKIT);
|
||||
+ this.marker = SerializableMeta.getBoolean(map, MARKER.BUKKIT);
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,6 +105,31 @@ public class CraftMetaArmorStand extends CraftMetaItem {
|
||||
void applyToItem(CompoundTag tag) {
|
||||
super.applyToItem(tag);
|
||||
|
||||
+ // Paper start
|
||||
+ if (!isArmorStandEmpty() && this.entityTag == null) {
|
||||
+ this.entityTag = new CompoundTag();
|
||||
+ }
|
||||
+
|
||||
+ if (isInvisible()) {
|
||||
+ this.entityTag.putBoolean(INVISIBLE.NBT, this.invisible);
|
||||
+ }
|
||||
+
|
||||
+ if (hasNoBasePlate()) {
|
||||
+ this.entityTag.putBoolean(NO_BASE_PLATE.NBT, this.noBasePlate);
|
||||
+ }
|
||||
+
|
||||
+ if (shouldShowArms()) {
|
||||
+ this.entityTag.putBoolean(SHOW_ARMS.NBT, this.showArms);
|
||||
+ }
|
||||
+
|
||||
+ if (isSmall()) {
|
||||
+ this.entityTag.putBoolean(SMALL.NBT, this.small);
|
||||
+ }
|
||||
+
|
||||
+ if (isMarker()) {
|
||||
+ this.entityTag.putBoolean(MARKER.NBT, this.marker);
|
||||
+ }
|
||||
+ // Paper end
|
||||
if (this.entityTag != null) {
|
||||
tag.put(ENTITY_TAG.NBT, entityTag);
|
||||
}
|
||||
@@ -78,7 +151,7 @@ public class CraftMetaArmorStand extends CraftMetaItem {
|
||||
}
|
||||
|
||||
boolean isArmorStandEmpty() {
|
||||
- return !(this.entityTag != null);
|
||||
+ return !(this.isInvisible() || this.hasNoBasePlate() || this.shouldShowArms() || this.isSmall() || this.isMarker() || this.entityTag != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,7 +162,13 @@ public class CraftMetaArmorStand extends CraftMetaItem {
|
||||
if (meta instanceof CraftMetaArmorStand) {
|
||||
CraftMetaArmorStand that = (CraftMetaArmorStand) meta;
|
||||
|
||||
- return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : this.entityTag == null;
|
||||
+ // Paper start
|
||||
+ return this.invisible == that.invisible &&
|
||||
+ this.noBasePlate == that.noBasePlate &&
|
||||
+ this.showArms == that.showArms &&
|
||||
+ this.small == that.small &&
|
||||
+ this.marker == that.marker;
|
||||
+ // Paper end
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -104,9 +183,14 @@ public class CraftMetaArmorStand extends CraftMetaItem {
|
||||
final int original;
|
||||
int hash = original = super.applyHash();
|
||||
|
||||
- if (this.entityTag != null) {
|
||||
- hash = 73 * hash + this.entityTag.hashCode();
|
||||
- }
|
||||
+ // Paper start
|
||||
+ hash += this.entityTag != null ? 73 * hash + this.entityTag.hashCode() : 0;
|
||||
+ hash += this.isInvisible() ? 61 * hash + 1231 : 0;
|
||||
+ hash += this.hasNoBasePlate() ? 61 * hash + 1231 : 0;
|
||||
+ hash += this.shouldShowArms() ? 61 * hash + 1231 : 0;
|
||||
+ hash += this.isSmall() ? 61 * hash + 1231 : 0;
|
||||
+ hash += this.isMarker() ? 61 * hash + 1231 : 0;
|
||||
+ // Paper end
|
||||
|
||||
return original != hash ? CraftMetaArmorStand.class.hashCode() ^ hash : hash;
|
||||
}
|
||||
@@ -115,6 +199,28 @@ public class CraftMetaArmorStand extends CraftMetaItem {
|
||||
Builder<String, Object> serialize(Builder<String, Object> builder) {
|
||||
super.serialize(builder);
|
||||
|
||||
+ // Paper start
|
||||
+ if (this.isInvisible()) {
|
||||
+ builder.put(INVISIBLE.BUKKIT, invisible);
|
||||
+ }
|
||||
+
|
||||
+ if (this.hasNoBasePlate()) {
|
||||
+ builder.put(NO_BASE_PLATE.BUKKIT, noBasePlate);
|
||||
+ }
|
||||
+
|
||||
+ if (this.shouldShowArms()) {
|
||||
+ builder.put(SHOW_ARMS.BUKKIT, showArms);
|
||||
+ }
|
||||
+
|
||||
+ if (this.isSmall()) {
|
||||
+ builder.put(SMALL.BUKKIT, small);
|
||||
+ }
|
||||
+
|
||||
+ if (this.isMarker()) {
|
||||
+ builder.put(MARKER.BUKKIT, marker);
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -128,4 +234,56 @@ public class CraftMetaArmorStand extends CraftMetaItem {
|
||||
|
||||
return clone;
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isInvisible() {
|
||||
+ return invisible;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasNoBasePlate() {
|
||||
+ return noBasePlate;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean shouldShowArms() {
|
||||
+ return showArms;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isSmall() {
|
||||
+ return small;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isMarker() {
|
||||
+ return marker;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setInvisible(boolean invisible) {
|
||||
+ this.invisible = invisible;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setNoBasePlate(boolean noBasePlate) {
|
||||
+ this.noBasePlate = noBasePlate;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setShowArms(boolean showArms) {
|
||||
+ this.showArms = showArms;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setSmall(boolean small) {
|
||||
+ this.small = small;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setMarker(boolean marker) {
|
||||
+ this.marker = marker;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
index 20d10e5b54edaf1c5212bbc33b8cd1aa426fa826..d5df6fc244ab82b94196be9c436ba77020716df2 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
|
||||
@@ -1452,6 +1452,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
|
||||
CraftMetaCrossbow.CHARGED.NBT,
|
||||
CraftMetaCrossbow.CHARGED_PROJECTILES.NBT,
|
||||
CraftMetaSuspiciousStew.EFFECTS.NBT,
|
||||
+ // Paper start
|
||||
+ CraftMetaArmorStand.ENTITY_TAG.NBT,
|
||||
+ CraftMetaArmorStand.INVISIBLE.NBT,
|
||||
+ CraftMetaArmorStand.NO_BASE_PLATE.NBT,
|
||||
+ CraftMetaArmorStand.SHOW_ARMS.NBT,
|
||||
+ CraftMetaArmorStand.SMALL.NBT,
|
||||
+ CraftMetaArmorStand.MARKER.NBT,
|
||||
+ // Paper end
|
||||
CraftMetaCompass.LODESTONE_DIMENSION.NBT,
|
||||
CraftMetaCompass.LODESTONE_POS.NBT,
|
||||
CraftMetaCompass.LODESTONE_TRACKED.NBT,
|
||||
diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java
|
||||
index a7505a08b952431d1dd7e4b332ede0c0d15eea64..f3a0578f53863dd0866b4c2cb957a30fa3bc6cc5 100644
|
||||
--- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java
|
||||
+++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java
|
||||
@@ -324,6 +324,7 @@ public class ItemMetaTest extends AbstractTestingBase {
|
||||
final CraftMetaArmorStand meta = (CraftMetaArmorStand) cleanStack.getItemMeta();
|
||||
meta.entityTag = new CompoundTag();
|
||||
meta.entityTag.putBoolean("Small", true);
|
||||
+ meta.setInvisible(true); // Paper
|
||||
cleanStack.setItemMeta(meta);
|
||||
return cleanStack;
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 11 Feb 2018 10:43:46 +0000
|
||||
Subject: [PATCH] Extend Player Interact cancellation
|
||||
|
||||
GUIs are opened on the client, meaning that the server cannot block them from opening,
|
||||
However, it is possible to close these GUIs from the server.
|
||||
|
||||
Flower pots are also not updated on the client when interaction is cancelled, this patch
|
||||
also resolves this.
|
||||
|
||||
Update adjacent blocks of doors, double plants, pistons and beds
|
||||
when cancelling interaction.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index c0f712fd4dd57080044341c7c7c8faf09572c2c5..91d6885da13138e1def16e1876910ef893ce244d 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -196,6 +196,11 @@ public class ServerPlayerGameMode {
|
||||
PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, pos, direction, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND);
|
||||
if (event.isCancelled()) {
|
||||
// Let the client know the block still exists
|
||||
+ // Paper start - brute force neighbor blocks for any attached blocks
|
||||
+ for (Direction dir : Direction.values()) {
|
||||
+ this.player.connection.send(new ClientboundBlockUpdatePacket(level, pos.relative(dir)));
|
||||
+ }
|
||||
+ // Paper end
|
||||
this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos));
|
||||
// Update any tile entity data for this block
|
||||
BlockEntity tileentity = this.level.getBlockEntity(pos);
|
||||
@@ -513,7 +518,13 @@ public class ServerPlayerGameMode {
|
||||
|
||||
// send a correcting update to the client for the block above as well, this because of replaceable blocks (such as grass, sea grass etc)
|
||||
player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above()));
|
||||
+ // Paper start - extend Player Interact cancellation // TODO: consider merging this into the extracted method
|
||||
+ } else if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.StructureBlock) {
|
||||
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId));
|
||||
+ } else if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.CommandBlock) {
|
||||
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId));
|
||||
}
|
||||
+ // Paper end - extend Player Interact cancellation
|
||||
player.getBukkitEntity().updateInventory(); // SPIGOT-2867
|
||||
enuminteractionresult = (event.useItemInHand() != Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
|
||||
} else if (this.gameModeForPlayer == GameType.SPECTATOR) {
|
|
@ -1,38 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 24 Feb 2018 01:14:55 -0500
|
||||
Subject: [PATCH] Tameable#getOwnerUniqueId API
|
||||
|
||||
This is faster if all you need is the UUID, as .getOwner() will cause
|
||||
an OfflinePlayer to be loaded from disk.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java
|
||||
index a5202ee012034678efbbd5ca1eccf2fd72a315bd..254d4f2e45d7c8f572a4368eccd84560d4d0d836 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java
|
||||
@@ -89,6 +89,10 @@ public abstract class CraftAbstractHorse extends CraftAnimals implements Abstrac
|
||||
}
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public UUID getOwnerUniqueId() {
|
||||
+ return getOwnerUUID();
|
||||
+ }
|
||||
public UUID getOwnerUUID() {
|
||||
return this.getHandle().getOwnerUUID();
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java
|
||||
index f225da459d0c9b5b5322ba3256e63880a7b4ad5d..428437970cac144be53cd0e30af7af0cd1ce603b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java
|
||||
@@ -17,6 +17,10 @@ public class CraftTameableAnimal extends CraftAnimals implements Tameable, Creat
|
||||
return (TamableAnimal) super.getHandle();
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public UUID getOwnerUniqueId() {
|
||||
+ return getOwnerUUID();
|
||||
+ }
|
||||
public UUID getOwnerUUID() {
|
||||
try {
|
||||
return this.getHandle().getOwnerUUID();
|
|
@ -1,34 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger <admin@benndorf.dev>
|
||||
Date: Sat, 10 Mar 2018 00:50:24 +0100
|
||||
Subject: [PATCH] Toggleable player crits, helps mitigate hacked clients.
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 99ce64e4d01b58d887506841451e561c2796c413..665b7f4cddfef1631ba2fad6eebeb19392cf8759 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -253,6 +253,11 @@ public class PaperWorldConfig {
|
||||
disableChestCatDetection = getBoolean("game-mechanics.disable-chest-cat-detection", false);
|
||||
}
|
||||
|
||||
+ public boolean disablePlayerCrits;
|
||||
+ private void disablePlayerCrits() {
|
||||
+ disablePlayerCrits = getBoolean("game-mechanics.disable-player-crits", false);
|
||||
+ }
|
||||
+
|
||||
public boolean allChunksAreSlimeChunks;
|
||||
private void allChunksAreSlimeChunks() {
|
||||
allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", false);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
index de71d57b86d681efe0916dbee53be3ac826f9e2e..66b474304f659efcc7bd1181e3eaee70657013eb 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1209,6 +1209,7 @@ public abstract class Player extends LivingEntity {
|
||||
|
||||
boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity;
|
||||
|
||||
+ flag2 = flag2 && !level.paperConfig.disablePlayerCrits; // Paper
|
||||
flag2 = flag2 && !this.isSprinting();
|
||||
if (flag2) {
|
||||
f *= 1.5F;
|
|
@ -1,34 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 11 Mar 2018 14:13:33 -0400
|
||||
Subject: [PATCH] Disable Explicit Network Manager Flushing
|
||||
|
||||
This seems completely pointless, as packet dispatch uses .writeAndFlush.
|
||||
|
||||
Things seem to work fine without explicit flushing, but incase issues arise,
|
||||
provide a System property to re-enable it using improved logic of doing the
|
||||
flushing on the netty event loop, so it won't do the flush on the main thread.
|
||||
|
||||
Renable flushing by passing -Dpaper.explicit-flush=true
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 1a2184e23f1e1b8e39141689ebc5f1d13d364038..7e7d33a843566440f815d779ef2f3db9efc3b92d 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -96,6 +96,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
// Paper start - NetworkClient implementation
|
||||
public int protocolVersion;
|
||||
public java.net.InetSocketAddress virtualHost;
|
||||
+ private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush");
|
||||
// Paper end
|
||||
|
||||
public Connection(PacketFlow side) {
|
||||
@@ -271,7 +272,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
}
|
||||
|
||||
if (this.channel != null) {
|
||||
- this.channel.flush();
|
||||
+ if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - we don't need to explicit flush here, but allow opt in incase issues are found to a better version
|
||||
}
|
||||
|
||||
if (this.tickCount++ % 20 == 0) {
|
|
@ -1,250 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Minecrell <minecrell@minecrell.net>
|
||||
Date: Wed, 11 Oct 2017 15:56:26 +0200
|
||||
Subject: [PATCH] Implement extended PaperServerListPingEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..4ecd0c5bbea55f68549c85aa27e80e2c7e6265d4
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java
|
||||
@@ -0,0 +1,31 @@
|
||||
+package com.destroystokyo.paper.network;
|
||||
+
|
||||
+import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.server.level.ServerPlayer;
|
||||
+import org.bukkit.entity.Player;
|
||||
+import org.bukkit.util.CachedServerIcon;
|
||||
+
|
||||
+import javax.annotation.Nullable;
|
||||
+
|
||||
+class PaperServerListPingEventImpl extends PaperServerListPingEvent {
|
||||
+
|
||||
+ private final MinecraftServer server;
|
||||
+
|
||||
+ PaperServerListPingEventImpl(MinecraftServer server, StatusClient client, int protocolVersion, @Nullable CachedServerIcon icon) {
|
||||
+ super(client, server.getMotd(), server.getPlayerCount(), server.getMaxPlayers(),
|
||||
+ server.getServerModName() + ' ' + server.getServerVersion(), protocolVersion, icon);
|
||||
+ this.server = server;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected final Object[] getOnlinePlayers() {
|
||||
+ return this.server.getPlayerList().players.toArray();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ protected final Player getBukkitPlayer(Object player) {
|
||||
+ return ((ServerPlayer) player).getBukkitEntity();
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java b/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d926ad804355ee2fdc5910b2505e8671602acdab
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java
|
||||
@@ -0,0 +1,11 @@
|
||||
+package com.destroystokyo.paper.network;
|
||||
+
|
||||
+import net.minecraft.network.Connection;
|
||||
+
|
||||
+class PaperStatusClient extends PaperNetworkClient implements StatusClient {
|
||||
+
|
||||
+ PaperStatusClient(Connection networkManager) {
|
||||
+ super(networkManager);
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..4c2351b03b58511b80017b58ee9b20ab5193adc9
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
|
||||
@@ -0,0 +1,110 @@
|
||||
+package com.destroystokyo.paper.network;
|
||||
+
|
||||
+import com.destroystokyo.paper.profile.CraftPlayerProfile;
|
||||
+import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
+import com.google.common.base.MoreObjects;
|
||||
+import com.google.common.base.Strings;
|
||||
+import com.mojang.authlib.GameProfile;
|
||||
+import io.papermc.paper.adventure.AdventureComponent;
|
||||
+import java.util.List;
|
||||
+import java.util.UUID;
|
||||
+import javax.annotation.Nonnull;
|
||||
+import net.minecraft.network.Connection;
|
||||
+import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
|
||||
+import net.minecraft.network.protocol.status.ServerStatus;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+
|
||||
+public final class StandardPaperServerListPingEventImpl extends PaperServerListPingEventImpl {
|
||||
+
|
||||
+ private static final GameProfile[] EMPTY_PROFILES = new GameProfile[0];
|
||||
+ private static final UUID FAKE_UUID = new UUID(0, 0);
|
||||
+
|
||||
+ private GameProfile[] originalSample;
|
||||
+
|
||||
+ private StandardPaperServerListPingEventImpl(MinecraftServer server, Connection networkManager, ServerStatus ping) {
|
||||
+ super(server, new PaperStatusClient(networkManager), ping.getVersion() != null ? ping.getVersion().getProtocol() : -1, server.server.getServerIcon());
|
||||
+ this.originalSample = ping.getPlayers() == null ? null : ping.getPlayers().getSample(); // GH-1473 - pre-tick race condition NPE
|
||||
+ }
|
||||
+
|
||||
+ @Nonnull
|
||||
+ @Override
|
||||
+ public List<PlayerProfile> getPlayerSample() {
|
||||
+ List<PlayerProfile> sample = super.getPlayerSample();
|
||||
+
|
||||
+ if (this.originalSample != null) {
|
||||
+ for (GameProfile profile : this.originalSample) {
|
||||
+ sample.add(CraftPlayerProfile.asBukkitCopy(profile));
|
||||
+ }
|
||||
+ this.originalSample = null;
|
||||
+ }
|
||||
+
|
||||
+ return sample;
|
||||
+ }
|
||||
+
|
||||
+ private GameProfile[] getPlayerSampleHandle() {
|
||||
+ if (this.originalSample != null) {
|
||||
+ return this.originalSample;
|
||||
+ }
|
||||
+
|
||||
+ List<PlayerProfile> entries = super.getPlayerSample();
|
||||
+ if (entries.isEmpty()) {
|
||||
+ return EMPTY_PROFILES;
|
||||
+ }
|
||||
+
|
||||
+ GameProfile[] profiles = new GameProfile[entries.size()];
|
||||
+ for (int i = 0; i < profiles.length; i++) {
|
||||
+ /*
|
||||
+ * Avoid null UUIDs/names since that will make the response invalid
|
||||
+ * on the client.
|
||||
+ * Instead, fall back to a fake/empty UUID and an empty string as name.
|
||||
+ * This can be used to create custom lines in the player list that do not
|
||||
+ * refer to a specific player.
|
||||
+ */
|
||||
+
|
||||
+ PlayerProfile profile = entries.get(i);
|
||||
+ if (profile.getId() != null && profile.getName() != null) {
|
||||
+ profiles[i] = CraftPlayerProfile.asAuthlib(profile);
|
||||
+ } else {
|
||||
+ profiles[i] = new GameProfile(MoreObjects.firstNonNull(profile.getId(), FAKE_UUID), Strings.nullToEmpty(profile.getName()));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return profiles;
|
||||
+ }
|
||||
+
|
||||
+ @SuppressWarnings("deprecation")
|
||||
+ public static void processRequest(MinecraftServer server, Connection networkManager) {
|
||||
+ StandardPaperServerListPingEventImpl event = new StandardPaperServerListPingEventImpl(server, networkManager, server.getStatus());
|
||||
+ server.server.getPluginManager().callEvent(event);
|
||||
+
|
||||
+ // Close connection immediately if event is cancelled
|
||||
+ if (event.isCancelled()) {
|
||||
+ networkManager.disconnect(null);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // Setup response
|
||||
+ ServerStatus ping = new ServerStatus();
|
||||
+
|
||||
+ // Description
|
||||
+ ping.setDescription(new AdventureComponent(event.motd()));
|
||||
+
|
||||
+ // Players
|
||||
+ if (!event.shouldHidePlayers()) {
|
||||
+ ping.setPlayers(new ServerStatus.Players(event.getMaxPlayers(), event.getNumPlayers()));
|
||||
+ ping.getPlayers().setSample(event.getPlayerSampleHandle());
|
||||
+ }
|
||||
+
|
||||
+ // Version
|
||||
+ ping.setVersion(new ServerStatus.Version(event.getVersion(), event.getProtocolVersion()));
|
||||
+
|
||||
+ // Favicon
|
||||
+ if (event.getServerIcon() != null) {
|
||||
+ ping.setFavicon(event.getServerIcon().getData());
|
||||
+ }
|
||||
+
|
||||
+ // Send response
|
||||
+ networkManager.send(new ClientboundStatusResponsePacket(ping));
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java b/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java
|
||||
index 67455a5ba75c9b816213e44d6872c5ddf8e27e98..23efad80934930beadf15e65781551d4ba7ff81b 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java
|
||||
@@ -10,7 +10,9 @@ import net.minecraft.util.GsonHelper;
|
||||
import net.minecraft.util.LowerCaseEnumTypeAdapterFactory;
|
||||
|
||||
public class ClientboundStatusResponsePacket implements Packet<ClientStatusPacketListener> {
|
||||
- private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(ServerStatus.Version.class, new ServerStatus.Version.Serializer()).registerTypeAdapter(ServerStatus.Players.class, new ServerStatus.Players.Serializer()).registerTypeAdapter(ServerStatus.class, new ServerStatus.Serializer()).registerTypeHierarchyAdapter(Component.class, new Component.Serializer()).registerTypeHierarchyAdapter(Style.class, new Style.Serializer()).registerTypeAdapterFactory(new LowerCaseEnumTypeAdapterFactory()).create();
|
||||
+ private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(ServerStatus.Version.class, new ServerStatus.Version.Serializer()).registerTypeAdapter(ServerStatus.Players.class, new ServerStatus.Players.Serializer()).registerTypeAdapter(ServerStatus.class, new ServerStatus.Serializer()).registerTypeHierarchyAdapter(Component.class, new Component.Serializer()).registerTypeHierarchyAdapter(Style.class, new Style.Serializer()).registerTypeAdapterFactory(new LowerCaseEnumTypeAdapterFactory())
|
||||
+ .registerTypeAdapter(io.papermc.paper.adventure.AdventureComponent.class, new io.papermc.paper.adventure.AdventureComponent.Serializer())
|
||||
+ .create();
|
||||
private final ServerStatus status;
|
||||
|
||||
public ClientboundStatusResponsePacket(ServerStatus metadata) {
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 22c4598e00d1a27d86584e7bfcbb73038f2f2c1a..c7881eebb02424ce488d2c04aa736f17402109a0 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -2,6 +2,9 @@ package net.minecraft.server;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
+import co.aikar.timings.Timings;
|
||||
+import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
|
||||
+import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -1350,7 +1353,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
this.lastServerStatus = i;
|
||||
this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount()));
|
||||
if (!this.hidesOnlinePlayers()) {
|
||||
- GameProfile[] agameprofile = new GameProfile[Math.min(this.getPlayerCount(), 12)];
|
||||
+ GameProfile[] agameprofile = new GameProfile[Math.min(this.getPlayerCount(), org.spigotmc.SpigotConfig.playerSample)]; // Paper
|
||||
int j = Mth.nextInt(this.random, 0, this.getPlayerCount() - agameprofile.length);
|
||||
|
||||
for (int k = 0; k < agameprofile.length; ++k) {
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
|
||||
index 2b24a41587fbe1fba70a0ab42d3dc33358f2ba2e..4fa79d37ff4e70c61672cce7c55257c46232c026 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
|
||||
@@ -47,6 +47,8 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
|
||||
this.connection.disconnect(ServerStatusPacketListenerImpl.DISCONNECT_REASON);
|
||||
} else {
|
||||
this.hasRequestedStatus = true;
|
||||
+ // Paper start - Replace everything
|
||||
+ /*
|
||||
// CraftBukkit start
|
||||
// this.connection.send(new PacketStatusOutServerInfo(this.server.getStatus()));
|
||||
final Object[] players = this.server.getPlayerList().players.toArray();
|
||||
@@ -150,6 +152,9 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
|
||||
|
||||
this.connection.send(new ClientboundStatusResponsePacket(ping));
|
||||
// CraftBukkit end
|
||||
+ */
|
||||
+ com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(this.server, this.connection);
|
||||
+ // Paper end
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
index cd5add5a38919dfcf7510758b2d3e2f7c40c18fd..b53e6955f35e1308814cdb31a5fa5f4d0c49493c 100644
|
||||
--- a/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
|
||||
@@ -289,7 +289,7 @@ public class SpigotConfig
|
||||
public static int playerSample;
|
||||
private static void playerSample()
|
||||
{
|
||||
- SpigotConfig.playerSample = SpigotConfig.getInt( "settings.sample-count", 12 );
|
||||
+ SpigotConfig.playerSample = Math.max( SpigotConfig.getInt( "settings.sample-count", 12 ), 0 ); // Paper - Avoid negative counts
|
||||
Bukkit.getLogger().log( Level.INFO, "Server Ping Player Sample Count: {0}", playerSample ); // Paper - Use logger
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 18 Mar 2018 11:45:57 -0400
|
||||
Subject: [PATCH] Ability to change PlayerProfile in AsyncPreLoginEvent
|
||||
|
||||
This will allow you to change the players name or skin on login.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 73efc3084b04914f7f06875651269fd584b60989..d3462cdc5eee37cedbff80f35d5b9c51e8dcd1da 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -343,8 +343,16 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
|
||||
java.util.UUID uniqueId = ServerLoginPacketListenerImpl.this.gameProfile.getId();
|
||||
final org.bukkit.craftbukkit.CraftServer server = ServerLoginPacketListenerImpl.this.server.server;
|
||||
|
||||
- AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId);
|
||||
+ // Paper start
|
||||
+ com.destroystokyo.paper.profile.PlayerProfile profile = org.bukkit.Bukkit.createProfile(uniqueId, playerName);
|
||||
+ AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId, profile);
|
||||
server.getPluginManager().callEvent(asyncEvent);
|
||||
+ profile = asyncEvent.getPlayerProfile();
|
||||
+ profile.complete();
|
||||
+ gameProfile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
|
||||
+ playerName = gameProfile.getName();
|
||||
+ uniqueId = gameProfile.getId();
|
||||
+ // Paper end
|
||||
|
||||
if (PlayerPreLoginEvent.getHandlerList().getRegisteredListeners().length != 0) {
|
||||
final PlayerPreLoginEvent event = new PlayerPreLoginEvent(playerName, address, uniqueId);
|
|
@ -1,145 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 18 Mar 2018 12:29:48 -0400
|
||||
Subject: [PATCH] Player.setPlayerProfile API
|
||||
|
||||
This can be useful for changing name or skins after a player has logged in.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index d3462cdc5eee37cedbff80f35d5b9c51e8dcd1da..5ebc450432805d52457b9f8ff1e2b1981bdd78e6 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -344,11 +344,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
|
||||
final org.bukkit.craftbukkit.CraftServer server = ServerLoginPacketListenerImpl.this.server.server;
|
||||
|
||||
// Paper start
|
||||
- com.destroystokyo.paper.profile.PlayerProfile profile = org.bukkit.Bukkit.createProfile(uniqueId, playerName);
|
||||
+ com.destroystokyo.paper.profile.PlayerProfile profile = com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitMirror(ServerLoginPacketListenerImpl.this.gameProfile);
|
||||
AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId, profile);
|
||||
server.getPluginManager().callEvent(asyncEvent);
|
||||
profile = asyncEvent.getPlayerProfile();
|
||||
- profile.complete();
|
||||
+ profile.complete(true); // Paper - setPlayerProfileAPI
|
||||
gameProfile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
|
||||
playerName = gameProfile.getName();
|
||||
uniqueId = gameProfile.getId();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 19e8ec4baf0967693121b2e3443d436f85f518ec..9ab4897d5d0b25fbdcb4a9889b7e73acd993a786 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -77,6 +77,7 @@ import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.level.GameType;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
+import net.minecraft.world.level.biome.BiomeManager;
|
||||
import net.minecraft.world.level.block.entity.SignBlockEntity;
|
||||
import net.minecraft.world.level.border.BorderChangeListener;
|
||||
import net.minecraft.world.level.saveddata.maps.MapDecoration;
|
||||
@@ -204,11 +205,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
return server.getPlayer(getUniqueId()) != null;
|
||||
}
|
||||
|
||||
- @Override
|
||||
- public PlayerProfile getPlayerProfile() {
|
||||
- return new CraftPlayerProfile(this.getProfile());
|
||||
- }
|
||||
-
|
||||
@Override
|
||||
public InetSocketAddress getAddress() {
|
||||
if (this.getHandle().connection == null) return null;
|
||||
@@ -1482,8 +1478,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
this.hiddenEntities.put(entity.getUniqueId(), hidingPlugins);
|
||||
|
||||
// Remove this entity from the hidden player's EntityTrackerEntry
|
||||
- ChunkMap tracker = ((ServerLevel) this.getHandle().level).getChunkSource().chunkMap;
|
||||
+ // Paper start
|
||||
Entity other = ((CraftEntity) entity).getHandle();
|
||||
+ unregisterEntity(other);
|
||||
+
|
||||
+ server.getPluginManager().callEvent(new PlayerHideEntityEvent(this, entity));
|
||||
+ }
|
||||
+ private void unregisterEntity(Entity other) {
|
||||
+ // Paper end
|
||||
+ ChunkMap tracker = ((ServerLevel) this.getHandle().level).getChunkSource().chunkMap;
|
||||
ChunkMap.TrackedEntity entry = tracker.entityMap.get(other.getId());
|
||||
if (entry != null) {
|
||||
entry.removePlayer(this.getHandle());
|
||||
@@ -1496,8 +1499,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
this.getHandle().connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.REMOVE_PLAYER, otherPlayer));
|
||||
}
|
||||
}
|
||||
-
|
||||
- server.getPluginManager().callEvent(new PlayerHideEntityEvent(this, entity));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1534,8 +1535,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
}
|
||||
this.hiddenEntities.remove(entity.getUniqueId());
|
||||
|
||||
- ChunkMap tracker = ((ServerLevel) this.getHandle().level).getChunkSource().chunkMap;
|
||||
+ // Paper start
|
||||
Entity other = ((CraftEntity) entity).getHandle();
|
||||
+ registerEntity(other);
|
||||
+
|
||||
+ server.getPluginManager().callEvent(new PlayerShowEntityEvent(this, entity));
|
||||
+ }
|
||||
+ private void registerEntity(Entity other) {
|
||||
+ ChunkMap tracker = ((ServerLevel) this.getHandle().level).getChunkSource().chunkMap;
|
||||
+ // Paper end
|
||||
|
||||
if (other instanceof ServerPlayer) {
|
||||
ServerPlayer otherPlayer = (ServerPlayer) other;
|
||||
@@ -1546,9 +1554,51 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
if (entry != null && !entry.seenBy.contains(this.getHandle().connection)) {
|
||||
entry.updatePlayer(this.getHandle());
|
||||
}
|
||||
+ }
|
||||
+ // Paper start
|
||||
+ private void reregisterPlayer(ServerPlayer player) {
|
||||
+ if (!hiddenEntities.containsKey(player.getUUID())) {
|
||||
+ unregisterEntity(player);
|
||||
+ registerEntity(player);
|
||||
+ }
|
||||
+ }
|
||||
+ public void setPlayerProfile(com.destroystokyo.paper.profile.PlayerProfile profile) {
|
||||
+ ServerPlayer self = getHandle();
|
||||
+ self.gameProfile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
|
||||
+ if (!self.sentListPacket) {
|
||||
+ return;
|
||||
+ }
|
||||
+ List<ServerPlayer> players = server.getServer().getPlayerList().players;
|
||||
+ for (ServerPlayer player : players) {
|
||||
+ player.getBukkitEntity().reregisterPlayer(self);
|
||||
+ }
|
||||
+ refreshPlayer();
|
||||
+ }
|
||||
+ public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() {
|
||||
+ return new com.destroystokyo.paper.profile.CraftPlayerProfile(this).clone();
|
||||
+ }
|
||||
|
||||
- server.getPluginManager().callEvent(new PlayerShowEntityEvent(this, entity));
|
||||
+ private void refreshPlayer() {
|
||||
+ ServerPlayer handle = getHandle();
|
||||
+
|
||||
+ Location loc = getLocation();
|
||||
+
|
||||
+ ServerGamePacketListenerImpl connection = handle.connection;
|
||||
+ reregisterPlayer(handle);
|
||||
+
|
||||
+ //Respawn the player then update their position and selected slot
|
||||
+ ServerLevel worldserver = handle.getLevel();
|
||||
+ connection.send(new net.minecraft.network.protocol.game.ClientboundRespawnPacket(worldserver.dimensionTypeRegistration(), worldserver.dimension(), BiomeManager.obfuscateSeed(worldserver.getSeed()), handle.gameMode.getGameModeForPlayer(), handle.gameMode.getPreviousGameModeForPlayer(), worldserver.isDebug(), worldserver.isFlat(), true));
|
||||
+ handle.onUpdateAbilities();
|
||||
+ connection.send(new net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch(), java.util.Collections.emptySet(), 0, false));
|
||||
+ net.minecraft.server.MinecraftServer.getServer().getPlayerList().sendAllPlayerInfo(handle);
|
||||
+
|
||||
+ if (this.isOp()) {
|
||||
+ this.setOp(false);
|
||||
+ this.setOp(true);
|
||||
+ }
|
||||
}
|
||||
+ // Paper end
|
||||
|
||||
public void onEntityRemove(Entity entity) {
|
||||
this.hiddenEntities.remove(entity.getUUID());
|
|
@ -1,40 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Thu, 22 Mar 2018 01:40:24 -0400
|
||||
Subject: [PATCH] getPlayerUniqueId API
|
||||
|
||||
Gets the unique ID of the player currently known as the specified player name
|
||||
In Offline Mode, will return an Offline UUID
|
||||
|
||||
This is a more performant way to obtain a UUID for a name than loading an OfflinePlayer
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 77c5180d36f09cfeb7a82c6e321793ac1a363a48..8d888beec17bdea0621116d3038bb3d72e4b3c5d 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1705,6 +1705,25 @@ public final class CraftServer implements Server {
|
||||
return recipients.size();
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Nullable
|
||||
+ public UUID getPlayerUniqueId(String name) {
|
||||
+ Player player = Bukkit.getPlayerExact(name);
|
||||
+ if (player != null) {
|
||||
+ return player.getUniqueId();
|
||||
+ }
|
||||
+ GameProfile profile;
|
||||
+ // Only fetch an online UUID in online mode
|
||||
+ if (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode()) {
|
||||
+ profile = console.getProfileCache().get(name).orElse(null);
|
||||
+ } else {
|
||||
+ // Make an OfflinePlayer using an offline mode UUID since the name has no profile
|
||||
+ profile = new GameProfile(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)), name);
|
||||
+ }
|
||||
+ return profile != null ? profile.getId() : null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
@Deprecated
|
||||
public OfflinePlayer getOfflinePlayer(String name) {
|
|
@ -1,370 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Fri, 16 Mar 2018 22:59:43 -0400
|
||||
Subject: [PATCH] Improved Async Task Scheduler
|
||||
|
||||
The Craft Scheduler still uses the primary thread for task scheduling.
|
||||
This results in the main thread still having to do work as part of the
|
||||
dispatching of async tasks.
|
||||
|
||||
If plugins make use of lots of async tasks, such as particle emitters
|
||||
that want to keep the logic off the main thread, the main thread still
|
||||
receives quite a bit of load from processing all of these queued tasks.
|
||||
|
||||
Additionally, resizing and managing the pending entries for all of
|
||||
these asynchronous tasks takes up time on the main thread too.
|
||||
|
||||
This commit replaces the implementation of the scheduler when working
|
||||
with asynchronous tasks, by forwarding calls to the new scheduler.
|
||||
|
||||
The Async Scheduler uses a single thread executor for "management" tasks.
|
||||
The Management Thread is responsible for all adding and dispatching of
|
||||
scheduled tasks.
|
||||
|
||||
The mainThreadHeartbeat will send a heartbeat task to the management thread
|
||||
with the currentTick value, so that it can find which tasks to execute.
|
||||
|
||||
Scheduling of an async tasks also dispatches a management task, ensuring
|
||||
that any Queue resizing operation occurs off of the main thread.
|
||||
|
||||
The async queue uses a complete separate PriorityQueue, ensuring that resize
|
||||
operations are decoupled from the sync tasks queue.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..3c1992e212a6d6f1db4d5b807b38d71913619fc0
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncScheduler.java
|
||||
@@ -0,0 +1,122 @@
|
||||
+/*
|
||||
+ * 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.destroystokyo.paper.ServerSchedulerReportingWrapper;
|
||||
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
+import org.bukkit.plugin.Plugin;
|
||||
+
|
||||
+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();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Task is not cancelled
|
||||
+ * @param runningTask
|
||||
+ * @return
|
||||
+ */
|
||||
+ static boolean isValid(CraftTask runningTask) {
|
||||
+ return runningTask.getPeriod() >= CraftTask.NO_REPEATING;
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
index d96292052633941102c052894bef747817b2998f..ea7ebbc2674df727cf44856f172731ee083b8800 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
@@ -78,7 +78,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
/**
|
||||
* Main thread logic only
|
||||
*/
|
||||
- private final PriorityQueue<CraftTask> pending = new PriorityQueue<CraftTask>(10,
|
||||
+ final PriorityQueue<CraftTask> pending = new PriorityQueue<CraftTask>(10, // Paper
|
||||
new Comparator<CraftTask>() {
|
||||
@Override
|
||||
public int compare(final CraftTask o1, final CraftTask o2) {
|
||||
@@ -95,12 +95,13 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
/**
|
||||
* These are tasks that are currently active. It's provided for 'viewing' the current state.
|
||||
*/
|
||||
- private final ConcurrentHashMap<Integer, CraftTask> runners = new ConcurrentHashMap<Integer, CraftTask>();
|
||||
+ final ConcurrentHashMap<Integer, CraftTask> runners = new ConcurrentHashMap<Integer, CraftTask>(); // Paper
|
||||
/**
|
||||
* The sync task that is currently running on the main thread.
|
||||
*/
|
||||
private volatile CraftTask currentTask = null;
|
||||
- private volatile int currentTick = -1;
|
||||
+ // Paper start - Improved Async Task Scheduler
|
||||
+ volatile int currentTick = -1;/*
|
||||
private final Executor executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("Craft Scheduler Thread - %d").build());
|
||||
private CraftAsyncDebugger debugHead = new CraftAsyncDebugger(-1, null, null) {
|
||||
@Override
|
||||
@@ -109,12 +110,31 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
}
|
||||
};
|
||||
private CraftAsyncDebugger debugTail = this.debugHead;
|
||||
+
|
||||
+ */ // Paper end
|
||||
private static final int RECENT_TICKS;
|
||||
|
||||
static {
|
||||
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
|
||||
@Override
|
||||
public int scheduleSyncDelayedTask(final Plugin plugin, final Runnable task) {
|
||||
return this.scheduleSyncDelayedTask(plugin, task, 0L);
|
||||
@@ -237,7 +257,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
} else if (period < CraftTask.NO_REPEATING) {
|
||||
period = CraftTask.NO_REPEATING;
|
||||
}
|
||||
- return this.handle(new CraftAsyncTask(this.runners, plugin, runnable, this.nextId(), period), delay);
|
||||
+ return this.handle(new CraftAsyncTask(this.asyncScheduler.runners, plugin, runnable, this.nextId(), period), delay); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -253,6 +273,11 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
if (taskId <= 0) {
|
||||
return;
|
||||
}
|
||||
+ // Paper start
|
||||
+ if (!this.isAsyncScheduler) {
|
||||
+ this.asyncScheduler.cancelTask(taskId);
|
||||
+ }
|
||||
+ // Paper end
|
||||
CraftTask task = this.runners.get(taskId);
|
||||
if (task != null) {
|
||||
task.cancel0();
|
||||
@@ -295,6 +320,11 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
@Override
|
||||
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() {
|
||||
@Override
|
||||
@@ -334,6 +364,13 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
|
||||
@Override
|
||||
public boolean isCurrentlyRunning(final int taskId) {
|
||||
+ // Paper start
|
||||
+ if (!this.isAsyncScheduler) {
|
||||
+ if (this.asyncScheduler.isCurrentlyRunning(taskId)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
final CraftTask task = this.runners.get(taskId);
|
||||
if (task == null) {
|
||||
return false;
|
||||
@@ -352,6 +389,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 = this.head.getNext(); task != null; task = task.getNext()) {
|
||||
if (task.getTaskId() == taskId) {
|
||||
return task.getPeriod() >= CraftTask.NO_REPEATING; // The task will run
|
||||
@@ -363,6 +405,12 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
|
||||
@Override
|
||||
public List<BukkitWorker> getActiveWorkers() {
|
||||
+ // Paper start
|
||||
+ if (!isAsyncScheduler) {
|
||||
+ //noinspection TailRecursion
|
||||
+ return this.asyncScheduler.getActiveWorkers();
|
||||
+ }
|
||||
+ // Paper end
|
||||
final ArrayList<BukkitWorker> workers = new ArrayList<BukkitWorker>();
|
||||
for (final CraftTask taskObj : this.runners.values()) {
|
||||
// Iterator will be a best-effort (may fail to grab very new values) if called from an async thread
|
||||
@@ -400,6 +448,11 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
pending.add(task);
|
||||
}
|
||||
}
|
||||
+ // Paper start
|
||||
+ if (!this.isAsyncScheduler) {
|
||||
+ pending.addAll(this.asyncScheduler.getPendingTasks());
|
||||
+ }
|
||||
+ // Paper end
|
||||
return pending;
|
||||
}
|
||||
|
||||
@@ -407,6 +460,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;
|
||||
this.parsePending();
|
||||
@@ -446,7 +504,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
this.parsePending();
|
||||
} else {
|
||||
//this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass())); // Paper
|
||||
- this.executor.execute(new ServerSchedulerReportingWrapper(task)); // Paper
|
||||
+ 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)
|
||||
}
|
||||
@@ -465,7 +523,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
//this.debugHead = this.debugHead.getNextHead(currentTick); // Paper
|
||||
}
|
||||
|
||||
- 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)) {
|
||||
@@ -474,7 +532,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(this.currentTick + delay);
|
||||
this.addTask(task);
|
||||
return task;
|
||||
@@ -498,8 +562,8 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
return id;
|
||||
}
|
||||
|
||||
- private void parsePending() {
|
||||
- MinecraftTimings.bukkitSchedulerPendingTimer.startTiming();
|
||||
+ void parsePending() { // Paper
|
||||
+ if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.startTiming(); // Paper
|
||||
CraftTask head = this.head;
|
||||
CraftTask task = head.getNext();
|
||||
CraftTask lastTask = head;
|
||||
@@ -518,7 +582,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
task.setNext(null);
|
||||
}
|
||||
this.head = lastTask;
|
||||
- MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming();
|
||||
+ if (!this.isAsyncScheduler) MinecraftTimings.bukkitSchedulerPendingTimer.stopTiming(); // Paper
|
||||
}
|
||||
|
||||
private boolean isReady(final int currentTick) {
|
|
@ -1,36 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Date: Mon, 26 Mar 2018 18:30:53 +0300
|
||||
Subject: [PATCH] Upstream config migrations
|
||||
|
||||
This patch contains config migrations for when upstream adds options
|
||||
which Paper already had.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
index a8de81b1a153525b2d0d6b01802b7733947527a2..e2fed9b89ec1acb63a140f0f67814587ab6942bc 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
|
||||
@@ -291,4 +291,23 @@ public class PaperConfig {
|
||||
private static void authenticationServersDownKickMessage() {
|
||||
authenticationServersDownKickMessage = Strings.emptyToNull(getString("messages.kick.authentication-servers-down", authenticationServersDownKickMessage));
|
||||
}
|
||||
+
|
||||
+ private static void savePlayerData() {
|
||||
+ Object val = config.get("settings.save-player-data");
|
||||
+ if (val instanceof Boolean) {
|
||||
+ SpigotConfig.disablePlayerDataSaving = !(Boolean) val;
|
||||
+ SpigotConfig.config.set("players.disable-saving", SpigotConfig.disablePlayerDataSaving);
|
||||
+ SpigotConfig.save();
|
||||
+ config.set("settings.save-player-data", null);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void namedEntityDeaths() {
|
||||
+ Object val = config.get("settings.log-named-entity-deaths");
|
||||
+ if (val instanceof Boolean bool && !bool) {
|
||||
+ SpigotConfig.logNamedDeaths = false;
|
||||
+ SpigotConfig.config.set("settings.log-named-deaths", false);
|
||||
+ SpigotConfig.save();
|
||||
+ }
|
||||
+ }
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Minecrell <minecrell@minecrell.net>
|
||||
Date: Wed, 11 Oct 2017 18:22:50 +0200
|
||||
Subject: [PATCH] Make legacy ping handler more reliable
|
||||
|
||||
The Minecraft server often fails to respond to old ("legacy") pings
|
||||
from old Minecraft versions using the protocol used before the switch
|
||||
to Netty in Minecraft 1.7.
|
||||
|
||||
Due to packet fragmentation[1], we might not have all needed bytes
|
||||
available when the LegacyPingHandler is called. In this case, it will
|
||||
run into an error, remove the handler and continue using the modern
|
||||
protocol.
|
||||
|
||||
This is unlikely to happen for the first two revisions of the legacy
|
||||
ping protocol (used in Minecraft 1.5.x and older) since the request
|
||||
consists of only one or two bytes, but happens frequently for the
|
||||
last/third revision introduced in Minecraft 1.6.
|
||||
|
||||
It has much larger, variable packet sizes due to the inclusion of
|
||||
the virtual host (the hostname/port used to connect to the server).
|
||||
|
||||
The solution[2] is simple: If we find more than two matching bytes,
|
||||
we buffer the remaining bytes until we have enough to fully read and
|
||||
respond to the request.
|
||||
|
||||
[1]: https://netty.io/wiki/user-guide-for-4.x.html#wiki-h3-11
|
||||
[2]: https://netty.io/wiki/user-guide-for-4.x.html#wiki-h4-13
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
index d86c2287cb9f4c8cf99e4374ef8a7135041670a1..2818495aa221f8195f095e39091bd478cebb3807 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
@@ -16,6 +16,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final int FAKE_PROTOCOL_VERSION = 127;
|
||||
private final ServerConnectionListener serverConnectionListener;
|
||||
+ private ByteBuf buf; // Paper
|
||||
|
||||
public LegacyQueryHandler(ServerConnectionListener networkIo) {
|
||||
this.serverConnectionListener = networkIo;
|
||||
@@ -24,6 +25,16 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
public void channelRead(ChannelHandlerContext channelhandlercontext, Object object) {
|
||||
ByteBuf bytebuf = (ByteBuf) object;
|
||||
|
||||
+ // Paper start - Make legacy ping handler more reliable
|
||||
+ if (this.buf != null) {
|
||||
+ try {
|
||||
+ readLegacy1_6(channelhandlercontext, bytebuf);
|
||||
+ } finally {
|
||||
+ bytebuf.release();
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end
|
||||
bytebuf.markReaderIndex();
|
||||
boolean flag = true;
|
||||
|
||||
@@ -54,6 +65,10 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
this.sendFlushAndClose(channelhandlercontext, this.createReply(s));
|
||||
break;
|
||||
default:
|
||||
+ // Paper start - Replace with improved version below
|
||||
+ if (bytebuf.readUnsignedByte() != 0x01 || bytebuf.readUnsignedByte() != 0xFA) return;
|
||||
+ readLegacy1_6(channelhandlercontext, bytebuf);
|
||||
+ /*
|
||||
boolean flag1 = bytebuf.readUnsignedByte() == 1;
|
||||
|
||||
flag1 &= bytebuf.readUnsignedByte() == 250;
|
||||
@@ -77,6 +92,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
} finally {
|
||||
bytebuf1.release();
|
||||
}
|
||||
+ */ // Paper end - Replace with improved version below
|
||||
}
|
||||
|
||||
bytebuf.release();
|
||||
@@ -94,6 +110,90 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private static String readLegacyString(ByteBuf buf) {
|
||||
+ int size = buf.readShort() * Character.BYTES;
|
||||
+ if (!buf.isReadable(size)) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ String result = buf.toString(buf.readerIndex(), size, StandardCharsets.UTF_16BE);
|
||||
+ buf.skipBytes(size); // toString doesn't increase readerIndex automatically
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
+ private void readLegacy1_6(ChannelHandlerContext ctx, ByteBuf part) {
|
||||
+ ByteBuf buf = this.buf;
|
||||
+
|
||||
+ if (buf == null) {
|
||||
+ this.buf = buf = ctx.alloc().buffer();
|
||||
+ buf.markReaderIndex();
|
||||
+ } else {
|
||||
+ buf.resetReaderIndex();
|
||||
+ }
|
||||
+
|
||||
+ buf.writeBytes(part);
|
||||
+
|
||||
+ if (!buf.isReadable(Short.BYTES + Short.BYTES + Byte.BYTES + Short.BYTES + Integer.BYTES)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ String s = readLegacyString(buf);
|
||||
+ if (s == null) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!s.equals("MC|PingHost")) {
|
||||
+ removeHandler(ctx);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!buf.isReadable(Short.BYTES) || !buf.isReadable(buf.readShort())) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ MinecraftServer server = this.serverConnectionListener.getServer();
|
||||
+ int protocolVersion = buf.readByte();
|
||||
+ String host = readLegacyString(buf);
|
||||
+ if (host == null) {
|
||||
+ removeHandler(ctx);
|
||||
+ return;
|
||||
+ }
|
||||
+ int port = buf.readInt();
|
||||
+
|
||||
+ if (buf.isReadable()) {
|
||||
+ removeHandler(ctx);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ buf.release();
|
||||
+ this.buf = null;
|
||||
+
|
||||
+ LOGGER.debug("Ping: (1.6) from {}", ctx.channel().remoteAddress());
|
||||
+
|
||||
+ String response = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d",
|
||||
+ Byte.MAX_VALUE, server.getServerVersion(), server.getMotd(), server.getPlayerCount(), server.getMaxPlayers());
|
||||
+ this.sendFlushAndClose(ctx, this.createReply(response));
|
||||
+ }
|
||||
+
|
||||
+ private void removeHandler(ChannelHandlerContext ctx) {
|
||||
+ ByteBuf buf = this.buf;
|
||||
+ this.buf = null;
|
||||
+
|
||||
+ buf.resetReaderIndex();
|
||||
+ ctx.pipeline().remove(this);
|
||||
+ ctx.fireChannelRead(buf);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void handlerRemoved(ChannelHandlerContext ctx) {
|
||||
+ if (this.buf != null) {
|
||||
+ this.buf.release();
|
||||
+ this.buf = null;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
private void sendFlushAndClose(ChannelHandlerContext ctx, ByteBuf buf) {
|
||||
ctx.pipeline().firstContext().writeAndFlush(buf).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Minecrell <minecrell@minecrell.net>
|
||||
Date: Wed, 11 Oct 2017 19:30:51 +0200
|
||||
Subject: [PATCH] Call PaperServerListPingEvent for legacy pings
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java b/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..74c012fd40491f1d870fbc1aa8c318a2197eb106
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java
|
||||
@@ -0,0 +1,73 @@
|
||||
+package com.destroystokyo.paper.network;
|
||||
+
|
||||
+import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import org.apache.commons.lang3.StringUtils;
|
||||
+import org.bukkit.ChatColor;
|
||||
+
|
||||
+import java.net.InetSocketAddress;
|
||||
+
|
||||
+import javax.annotation.Nullable;
|
||||
+
|
||||
+public final class PaperLegacyStatusClient implements StatusClient {
|
||||
+
|
||||
+ private final InetSocketAddress address;
|
||||
+ private final int protocolVersion;
|
||||
+ @Nullable private final InetSocketAddress virtualHost;
|
||||
+
|
||||
+ private PaperLegacyStatusClient(InetSocketAddress address, int protocolVersion, @Nullable InetSocketAddress virtualHost) {
|
||||
+ this.address = address;
|
||||
+ this.protocolVersion = protocolVersion;
|
||||
+ this.virtualHost = virtualHost;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public InetSocketAddress getAddress() {
|
||||
+ return this.address;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getProtocolVersion() {
|
||||
+ return this.protocolVersion;
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ @Override
|
||||
+ public InetSocketAddress getVirtualHost() {
|
||||
+ return this.virtualHost;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isLegacy() {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ public static PaperServerListPingEvent processRequest(MinecraftServer server,
|
||||
+ InetSocketAddress address, int protocolVersion, @Nullable InetSocketAddress virtualHost) {
|
||||
+
|
||||
+ PaperServerListPingEvent event = new PaperServerListPingEventImpl(server,
|
||||
+ new PaperLegacyStatusClient(address, protocolVersion, virtualHost), Byte.MAX_VALUE, null);
|
||||
+ server.server.getPluginManager().callEvent(event);
|
||||
+
|
||||
+ if (event.isCancelled()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return event;
|
||||
+ }
|
||||
+
|
||||
+ public static String getMotd(PaperServerListPingEvent event) {
|
||||
+ return getFirstLine(event.getMotd());
|
||||
+ }
|
||||
+
|
||||
+ public static String getUnformattedMotd(PaperServerListPingEvent event) {
|
||||
+ // Strip color codes and all other occurrences of the color char (because it's used as delimiter)
|
||||
+ return getFirstLine(StringUtils.remove(ChatColor.stripColor(event.getMotd()), ChatColor.COLOR_CHAR));
|
||||
+ }
|
||||
+
|
||||
+ private static String getFirstLine(String s) {
|
||||
+ int pos = s.indexOf('\n');
|
||||
+ return pos >= 0 ? s.substring(0, pos) : s;
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
index 2818495aa221f8195f095e39091bd478cebb3807..53e87ea23dacd123cc47bd8ca43d0f19e69acaf2 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
|
||||
@@ -47,12 +47,19 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
MinecraftServer minecraftserver = this.serverConnectionListener.getServer();
|
||||
int i = bytebuf.readableBytes();
|
||||
String s;
|
||||
- org.bukkit.event.server.ServerListPingEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callServerListPingEvent(minecraftserver.server, inetsocketaddress.getAddress(), minecraftserver.getMotd(), minecraftserver.getPlayerCount(), minecraftserver.getMaxPlayers()); // CraftBukkit
|
||||
+ //org.bukkit.event.server.ServerListPingEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callServerListPingEvent(minecraftserver.server, inetsocketaddress.getAddress(), minecraftserver.getMotd(), minecraftserver.getPlayerCount(), minecraftserver.getMaxPlayers()); // CraftBukkit // Paper
|
||||
+ com.destroystokyo.paper.event.server.PaperServerListPingEvent event; // Paper
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
LegacyQueryHandler.LOGGER.debug("Ping: (<1.3.x) from {}:{}", inetsocketaddress.getAddress(), inetsocketaddress.getPort());
|
||||
- s = String.format("%s\u00a7%d\u00a7%d", event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); // CraftBukkit
|
||||
+ // Paper start - Call PaperServerListPingEvent and use results
|
||||
+ event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(minecraftserver, inetsocketaddress, 39, null);
|
||||
+ if (event == null) {
|
||||
+ channelhandlercontext.close();
|
||||
+ break;
|
||||
+ }
|
||||
+ s = String.format("%s\u00a7%d\u00a7%d", com.destroystokyo.paper.network.PaperLegacyStatusClient.getUnformattedMotd(event), event.getNumPlayers(), event.getMaxPlayers());
|
||||
this.sendFlushAndClose(channelhandlercontext, this.createReply(s));
|
||||
break;
|
||||
case 1:
|
||||
@@ -61,7 +68,14 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
|
||||
LegacyQueryHandler.LOGGER.debug("Ping: (1.4-1.5.x) from {}:{}", inetsocketaddress.getAddress(), inetsocketaddress.getPort());
|
||||
- s = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, minecraftserver.getServerVersion(), event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); // CraftBukkit
|
||||
+ // Paper start - Call PaperServerListPingEvent and use results
|
||||
+ event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(minecraftserver, inetsocketaddress, 127, null); // Paper
|
||||
+ if (event == null) {
|
||||
+ channelhandlercontext.close();
|
||||
+ break;
|
||||
+ }
|
||||
+ s = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", new Object[] { event.getProtocolVersion(), minecraftserver.getServerVersion(), event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()}); // CraftBukkit
|
||||
+ // Paper end
|
||||
this.sendFlushAndClose(channelhandlercontext, this.createReply(s));
|
||||
break;
|
||||
default:
|
||||
@@ -171,8 +185,16 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
LOGGER.debug("Ping: (1.6) from {}", ctx.channel().remoteAddress());
|
||||
|
||||
- String response = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d",
|
||||
- Byte.MAX_VALUE, server.getServerVersion(), server.getMotd(), server.getPlayerCount(), server.getMaxPlayers());
|
||||
+ InetSocketAddress virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(host, port);
|
||||
+ com.destroystokyo.paper.event.server.PaperServerListPingEvent event = com.destroystokyo.paper.network.PaperLegacyStatusClient.processRequest(
|
||||
+ server, (InetSocketAddress) ctx.channel().remoteAddress(), protocolVersion, virtualHost);
|
||||
+ if (event == null) {
|
||||
+ ctx.close();
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ String response = String.format("\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", event.getProtocolVersion(), event.getVersion(),
|
||||
+ com.destroystokyo.paper.network.PaperLegacyStatusClient.getMotd(event), event.getNumPlayers(), event.getMaxPlayers());
|
||||
this.sendFlushAndClose(ctx, this.createReply(response));
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sat, 31 Mar 2018 17:04:26 +0100
|
||||
Subject: [PATCH] Flag to disable the channel limit
|
||||
|
||||
In some enviroments, the channel limit set by spigot can cause issues,
|
||||
e.g. servers which allow and support the usage of mod packs.
|
||||
|
||||
provide an optional flag to disable this check, at your own risk.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 9ab4897d5d0b25fbdcb4a9889b7e73acd993a786..4fd3b8d55edd44cfc0cfb58f5e623a04426d7edf 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -170,6 +170,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
// Paper start
|
||||
private org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus;
|
||||
private String resourcePackHash;
|
||||
+ private static final boolean DISABLE_CHANNEL_LIMIT = System.getProperty("paper.disableChannelLimit") != null; // Paper - add a flag to disable the channel limit
|
||||
// Paper end
|
||||
|
||||
public CraftPlayer(CraftServer server, ServerPlayer entity) {
|
||||
@@ -1798,7 +1799,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
// Paper end
|
||||
|
||||
public void addChannel(String channel) {
|
||||
- Preconditions.checkState(this.channels.size() < 128, "Cannot register channel '%s'. Too many channels registered!", channel);
|
||||
+ Preconditions.checkState(DISABLE_CHANNEL_LIMIT || this.channels.size() < 128, "Cannot register channel '%s'. Too many channels registered!", channel); // Paper - flag to disable channel limit
|
||||
channel = StandardMessenger.validateAndCorrectChannel(channel);
|
||||
if (this.channels.add(channel)) {
|
||||
server.getPluginManager().callEvent(new PlayerRegisterChannelEvent(this, channel));
|
|
@ -1,46 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
|
||||
Date: Sun, 1 Apr 2018 02:29:37 +0300
|
||||
Subject: [PATCH] Add openSign method to HumanEntity
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
|
||||
index 26f21754b5ec3d1cbd455c4d9d04af299fc10b1b..09ea221665bd17bc853274d0146987ebadefe46f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
|
||||
@@ -118,15 +118,15 @@ public class CraftSign extends CraftBlockEntityState<SignBlockEntity> implements
|
||||
}
|
||||
}
|
||||
|
||||
- public static void openSign(Sign sign, Player player) {
|
||||
+ public static void openSign(Sign sign, org.bukkit.entity.HumanEntity player) { // Paper - change move open sign to HumanEntity
|
||||
Preconditions.checkArgument(sign != null, "sign == null");
|
||||
- Preconditions.checkArgument(sign.isPlaced(), "Sign must be placed");
|
||||
+ // Preconditions.checkArgument(sign.isPlaced(), "Sign must be placed"); // Paper - don't require placed
|
||||
Preconditions.checkArgument(sign.getWorld() == player.getWorld(), "Sign must be in same world as Player");
|
||||
|
||||
SignBlockEntity handle = ((CraftSign) sign).getTileEntity();
|
||||
handle.isEditable = true;
|
||||
|
||||
- ((CraftPlayer) player).getHandle().openTextEdit(handle);
|
||||
+ ((org.bukkit.craftbukkit.entity.CraftHumanEntity) player).getHandle().openTextEdit(handle); // Paper - change move open sign to HumanEntity
|
||||
}
|
||||
|
||||
// Paper start
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
index 013e68d483a1c2e707b61bfd0e2859fdc093fffa..6c708f65b3a3718c7b53e0c2cc12ee8ad62ff2b9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
@@ -613,6 +613,12 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - move open sign method to HumanEntity
|
||||
+ @Override
|
||||
+ public void openSign(org.bukkit.block.Sign sign) {
|
||||
+ org.bukkit.craftbukkit.block.CraftSign.openSign(sign, this);
|
||||
+ }
|
||||
+ // Paper end
|
||||
@Override
|
||||
public boolean dropItem(boolean dropAll) {
|
||||
if (!(this.getHandle() instanceof ServerPlayer)) return false;
|
|
@ -1,38 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Brokkonaut <hannos17@gmx.de>
|
||||
Date: Sat, 14 Apr 2018 20:20:46 +0200
|
||||
Subject: [PATCH] Configurable sprint interruption on attack
|
||||
|
||||
If the sprint interruption is disabled players continue sprinting when they attack entities.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 665b7f4cddfef1631ba2fad6eebeb19392cf8759..7dbd03897bf98ef19509972fb8d09aa071d7de3a 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -414,4 +414,9 @@ public class PaperWorldConfig {
|
||||
disableCreeperLingeringEffect = getBoolean("disable-creeper-lingering-effect", false);
|
||||
log("Creeper lingering effect: " + disableCreeperLingeringEffect);
|
||||
}
|
||||
+
|
||||
+ public boolean disableSprintInterruptionOnAttack;
|
||||
+ private void disableSprintInterruptionOnAttack() {
|
||||
+ disableSprintInterruptionOnAttack = getBoolean("game-mechanics.disable-sprint-interruption-on-attack", false);
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
index 66b474304f659efcc7bd1181e3eaee70657013eb..7b81d77649997aeb97cd819f380bdfe848702164 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1258,7 +1258,11 @@ public abstract class Player extends LivingEntity {
|
||||
}
|
||||
|
||||
this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D));
|
||||
- this.setSprinting(false);
|
||||
+ // Paper start - Configuration option to disable automatic sprint interruption
|
||||
+ if (!level.paperConfig.disableSprintInterruptionOnAttack) {
|
||||
+ this.setSprinting(false);
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
if (flag3) {
|
|
@ -1,22 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: 0x22 <0x22@futureclient.net>
|
||||
Date: Thu, 26 Apr 2018 04:41:11 -0400
|
||||
Subject: [PATCH] Fix exploit that allowed colored signs to be created
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index ee482d8942a355d989a2c913c23245bdbfb866a1..ba368d11aac5f440dfb45d0c283013390bb2aeff 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2811,9 +2811,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
||||
TextFilter.FilteredText currentLine = signText.get(i);
|
||||
|
||||
if (this.player.isTextFilteringEnabled()) {
|
||||
- lines.add(net.kyori.adventure.text.Component.text(currentLine.getFiltered()));
|
||||
+ lines.add(net.kyori.adventure.text.Component.text(SharedConstants.filterText(currentLine.getFiltered())));
|
||||
} else {
|
||||
- lines.add(net.kyori.adventure.text.Component.text(currentLine.getRaw()));
|
||||
+ lines.add(net.kyori.adventure.text.Component.text(SharedConstants.filterText(currentLine.getRaw())));
|
||||
}
|
||||
}
|
||||
SignChangeEvent event = new SignChangeEvent((org.bukkit.craftbukkit.block.CraftBlock) player.getWorld().getBlockAt(x, y, z), this.player.getBukkitEntity(), lines);
|
|
@ -1,65 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 30 Apr 2018 13:15:55 -0400
|
||||
Subject: [PATCH] EndermanEscapeEvent
|
||||
|
||||
Fires an event anytime an enderman intends to teleport away from the player
|
||||
|
||||
You may cancel this, enabling ranged attacks to damage the enderman for example.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
index 78c31a7191a5811732339e5bf8a7f07ef299a324..1decbe53207e25ee34f9948c4dcc79fa6f1138bc 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
@@ -113,6 +113,12 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
this.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.UNKNOWN, true);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ private boolean tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason reason) {
|
||||
+ return new com.destroystokyo.paper.event.entity.EndermanEscapeEvent((org.bukkit.craftbukkit.entity.CraftEnderman) this.getBukkitEntity(), reason).callEvent();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public boolean setTarget(LivingEntity entityliving, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent) {
|
||||
if (!super.setTarget(entityliving, reason, fireEvent)) {
|
||||
@@ -267,7 +273,7 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
if (this.level.isDay() && this.tickCount >= this.targetChangeTime + 600) {
|
||||
float f = this.getBrightness();
|
||||
|
||||
- if (f > 0.5F && this.level.canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F) {
|
||||
+ if (f > 0.5F && this.level.canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper
|
||||
this.setTarget((LivingEntity) null);
|
||||
this.teleport();
|
||||
}
|
||||
@@ -374,17 +380,19 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
flag = false;
|
||||
}
|
||||
|
||||
+ if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper start
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
if (this.teleport()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+ } // Paper end
|
||||
|
||||
return flag;
|
||||
} else {
|
||||
boolean flag1 = super.hurt(source, amount);
|
||||
|
||||
- if (!this.level.isClientSide() && !(source.getEntity() instanceof LivingEntity) && this.random.nextInt(10) != 0) {
|
||||
+ if (!this.level.isClientSide() && !(source.getEntity() instanceof LivingEntity) && this.random.nextInt(10) != 0 && this.tryEscape(source == DamageSource.DROWN ? com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.DROWN : com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - use to be critical hits as else, but mojang removed critical hits in 1.16.2 due to MC-185684
|
||||
this.teleport();
|
||||
}
|
||||
|
||||
@@ -604,7 +612,7 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
} else {
|
||||
if (this.target != null && !this.enderman.isPassenger()) {
|
||||
if (this.enderman.isLookingAtMe((Player) this.target)) {
|
||||
- if (this.target.distanceToSqr((Entity) this.enderman) < 16.0D) {
|
||||
+ if (this.target.distanceToSqr((Entity) this.enderman) < 16.0D && this.enderman.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.STARE)) { // Paper
|
||||
this.enderman.teleport();
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 30 Apr 2018 13:29:44 -0400
|
||||
Subject: [PATCH] Enderman.teleportRandomly()
|
||||
|
||||
Ability to trigger the vanilla "teleport randomly" mechanic of an enderman.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
index 1decbe53207e25ee34f9948c4dcc79fa6f1138bc..47f745bb54ab53674f371cb9dfc580fdb770541c 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
@@ -282,7 +282,7 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
super.customServerAiStep();
|
||||
}
|
||||
|
||||
- protected boolean teleport() {
|
||||
+ public boolean teleport() { // Paper - protected->public
|
||||
if (!this.level.isClientSide() && this.isAlive()) {
|
||||
double d0 = this.getX() + (this.random.nextDouble() - 0.5D) * 64.0D;
|
||||
double d1 = this.getY() + (double) (this.random.nextInt(64) - 32);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java
|
||||
index b72d7ade10075a13a617a370e2b8021326c9478d..ae669a970aa1f17ed786640de8a481364543c58e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderman.java
|
||||
@@ -16,6 +16,7 @@ public class CraftEnderman extends CraftMonster implements Enderman {
|
||||
super(server, entity);
|
||||
}
|
||||
|
||||
+ @Override public boolean teleportRandomly() { return getHandle().teleport(); } // Paper
|
||||
@Override
|
||||
public MaterialData getCarriedMaterial() {
|
||||
BlockState blockData = this.getHandle().getCarriedBlock();
|
|
@ -1,57 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 30 Apr 2018 17:15:26 -0400
|
||||
Subject: [PATCH] Block Enderpearl Travel Exploit
|
||||
|
||||
Players are able to use alt accounts and enderpearls to travel
|
||||
long distances utilizing the pearls in unloaded chunks and loading
|
||||
the chunk later when convenient.
|
||||
|
||||
This disables that by not saving the thrower when the chunk is unloaded.
|
||||
|
||||
This is mainly useful for survival servers that do not allow freeform teleporting.
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
index 7dbd03897bf98ef19509972fb8d09aa071d7de3a..0129a469d991225a0cef281e0e0eeb069fe4cfb5 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
||||
@@ -419,4 +419,10 @@ public class PaperWorldConfig {
|
||||
private void disableSprintInterruptionOnAttack() {
|
||||
disableSprintInterruptionOnAttack = getBoolean("game-mechanics.disable-sprint-interruption-on-attack", false);
|
||||
}
|
||||
+
|
||||
+ public boolean disableEnderpearlExploit = true;
|
||||
+ private void disableEnderpearlExploit() {
|
||||
+ disableEnderpearlExploit = getBoolean("game-mechanics.disable-unloaded-chunk-enderpearl-exploit", disableEnderpearlExploit);
|
||||
+ log("Disable Unloaded Chunk Enderpearl Exploit: " + (disableEnderpearlExploit ? "enabled" : "disabled"));
|
||||
+ }
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index 9769977c9db77aa52b99b793ca4f5d0c7b54528f..eb6981ca27d27946c748047660ced880c4dea01a 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1991,6 +1991,12 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
|
||||
public void onTickingEnd(Entity entity) {
|
||||
ServerLevel.this.entityTickList.remove(entity);
|
||||
+ // Paper start - Reset pearls when they stop being ticked
|
||||
+ if (paperConfig.disableEnderpearlExploit && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) {
|
||||
+ pearl.cachedOwner = null;
|
||||
+ pearl.ownerUUID = null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
public void onTrackingStart(Entity entity) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
||||
index 1c3ae7c61c06f486e50e57f434b9f360c6cf55be..bdefda914a7f93b8393a06f112ea9239d9685d51 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
|
||||
@@ -88,6 +88,7 @@ public abstract class Projectile extends Entity {
|
||||
protected void readAdditionalSaveData(CompoundTag nbt) {
|
||||
if (nbt.hasUUID("Owner")) {
|
||||
this.ownerUUID = nbt.getUUID("Owner");
|
||||
+ if (this instanceof ThrownEnderpearl && this.level != null && this.level.paperConfig.disableEnderpearlExploit) { this.ownerUUID = null; } // Paper - Don't store shooter name for pearls to block enderpearl travel exploit
|
||||
}
|
||||
|
||||
this.leftOwner = nbt.getBoolean("LeftOwner");
|
|
@ -1,58 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 15 Aug 2017 22:29:12 -0400
|
||||
Subject: [PATCH] Expand World.spawnParticle API and add Builder
|
||||
|
||||
Adds ability to control who receives it and who is the source/sender (vanish API)
|
||||
the standard API is to send the packet to everyone in the world, which is ineffecient.
|
||||
Adds an option to control the force mode of the particle.
|
||||
|
||||
This adds a new Builder API which is much friendlier to use.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
index eb6981ca27d27946c748047660ced880c4dea01a..3cb4a84a08cbf76e39da5f25fea490c26c77a289 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1390,12 +1390,17 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
||||
}
|
||||
|
||||
public <T extends ParticleOptions> int sendParticles(ServerPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) {
|
||||
+ // Paper start - Particle API Expansion
|
||||
+ return sendParticles(players, sender, t0, d0, d1, d2, i, d3, d4, d5, d6, force);
|
||||
+ }
|
||||
+ public <T extends ParticleOptions> int sendParticles(List<ServerPlayer> receivers, ServerPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) {
|
||||
+ // Paper end
|
||||
ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(t0, force, d0, d1, d2, (float) d3, (float) d4, (float) d5, (float) d6, i);
|
||||
// CraftBukkit end
|
||||
int j = 0;
|
||||
|
||||
- for (int k = 0; k < this.players.size(); ++k) {
|
||||
- ServerPlayer entityplayer = (ServerPlayer) this.players.get(k);
|
||||
+ for (Player entityhuman : receivers) { // Paper - Particle API Expansion
|
||||
+ ServerPlayer entityplayer = (ServerPlayer) entityhuman; // Paper - Particle API Expansion
|
||||
if (sender != null && !entityplayer.getBukkitEntity().canSee(sender.getBukkitEntity())) continue; // CraftBukkit
|
||||
|
||||
if (this.sendParticles(entityplayer, force, d0, d1, d2, packetplayoutworldparticles)) { // CraftBukkit
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 982b6dabf2aa8ac79596a235ffff1be948492b72..4a83fa80d11a5ef840cd556f845b4de84b3ad5f1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -1813,11 +1813,17 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public <T> void spawnParticle(Particle particle, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) {
|
||||
+ // Paper start - Particle API Expansion
|
||||
+ spawnParticle(particle, null, null, x, y, z, count, offsetX, offsetY, offsetZ, extra, data, force);
|
||||
+ }
|
||||
+ public <T> void spawnParticle(Particle particle, List<Player> receivers, Player sender, double x, double y, double z, int count, double offsetX, double offsetY, double offsetZ, double extra, T data, boolean force) {
|
||||
+ // Paper end
|
||||
if (data != null && !particle.getDataType().isInstance(data)) {
|
||||
throw new IllegalArgumentException("data should be " + particle.getDataType() + " got " + data.getClass());
|
||||
}
|
||||
this.getHandle().sendParticles(
|
||||
- null, // Sender
|
||||
+ receivers == null ? getHandle().players() : receivers.stream().map(player -> ((CraftPlayer) player).getHandle()).collect(java.util.stream.Collectors.toList()), // Paper - Particle API Expansion
|
||||
+ sender != null ? ((CraftPlayer) sender).getHandle() : null, // Sender // Paper - Particle API Expansion
|
||||
CraftParticle.toNMS(particle, data), // Particle
|
||||
x, y, z, // Position
|
||||
count, // Count
|
|
@ -1,33 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 10 Mar 2018 16:33:15 -0500
|
||||
Subject: [PATCH] Prevent Frosted Ice from loading/holding chunks
|
||||
|
||||
1.17: Shouldn't be needed as blocks no longer tick without at least 1 radius chunk loaded.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
|
||||
index 48776edab1479b5e861eca8146da04ebee01c46a..4f27969196fe21b38e81d070fe5c0a999dd320dc 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
|
||||
@@ -38,7 +38,8 @@ public class FrostedIceBlock extends IceBlock {
|
||||
|
||||
for(Direction direction : Direction.values()) {
|
||||
mutableBlockPos.setWithOffset(pos, direction);
|
||||
- BlockState blockState = world.getBlockState(mutableBlockPos);
|
||||
+ BlockState blockState = world.getBlockStateIfLoaded(mutableBlockPos); // Paper
|
||||
+ if (blockState == null) { continue; } // Paper
|
||||
if (blockState.is(this) && !this.slightlyMelt(blockState, world, mutableBlockPos)) {
|
||||
world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, world.paperConfig.frostedIceDelayMin, world.paperConfig.frostedIceDelayMax)); // Paper - use configurable min/max delay
|
||||
}
|
||||
@@ -75,7 +76,10 @@ public class FrostedIceBlock extends IceBlock {
|
||||
|
||||
for(Direction direction : Direction.values()) {
|
||||
mutableBlockPos.setWithOffset(pos, direction);
|
||||
- if (world.getBlockState(mutableBlockPos).is(this)) {
|
||||
+ // Paper start
|
||||
+ BlockState blockState = world.getBlockStateIfLoaded(mutableBlockPos);
|
||||
+ if (blockState != null && blockState.is(this)) {
|
||||
+ // Paper end
|
||||
++i;
|
||||
if (i >= maxNeighbors) {
|
||||
return false;
|
|
@ -1,30 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 1 May 2018 20:18:54 -0400
|
||||
Subject: [PATCH] EndermanAttackPlayerEvent
|
||||
|
||||
Allow control over whether or not an enderman aggros a player.
|
||||
|
||||
This allows you to override/extend the pumpkin/stare logic.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
index 47f745bb54ab53674f371cb9dfc580fdb770541c..102cab5a2104d32440ad489847bb7a443beead51 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
|
||||
@@ -225,7 +225,15 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
this.readPersistentAngerSaveData(this.level, nbt);
|
||||
}
|
||||
|
||||
- boolean isLookingAtMe(Player player) {
|
||||
+ // Paper start - EndermanAttackPlayerEvent
|
||||
+ private boolean isLookingAtMe(Player player) {
|
||||
+ boolean shouldAttack = isLookingAtMe_check(player);
|
||||
+ com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) player.getBukkitEntity());
|
||||
+ event.setCancelled(!shouldAttack);
|
||||
+ return event.callEvent();
|
||||
+ }
|
||||
+ private boolean isLookingAtMe_check(Player player) {
|
||||
+ // Paper end
|
||||
ItemStack itemstack = (ItemStack) player.getInventory().armor.get(3);
|
||||
|
||||
if (itemstack.is(Blocks.CARVED_PUMPKIN.asItem())) {
|
|
@ -1,24 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Wed, 16 May 2018 20:35:16 -0400
|
||||
Subject: [PATCH] WitchConsumePotionEvent
|
||||
|
||||
Fires when a witch consumes the potion in their hand
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Witch.java b/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
||||
index 1b9d1262f60224819dcd77acf09798bfc1895369..312726d7d9030146b0db432493b2efbd5e42847a 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java
|
||||
@@ -123,7 +123,11 @@ public class Witch extends Raider implements RangedAttackMob {
|
||||
|
||||
this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
|
||||
if (itemstack.is(Items.POTION)) {
|
||||
- List<MobEffectInstance> list = PotionUtils.getMobEffects(itemstack);
|
||||
+ // Paper start
|
||||
+ com.destroystokyo.paper.event.entity.WitchConsumePotionEvent event = new com.destroystokyo.paper.event.entity.WitchConsumePotionEvent((org.bukkit.entity.Witch) this.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack));
|
||||
+
|
||||
+ List<MobEffectInstance> list = event.callEvent() ? PotionUtils.getMobEffects(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getPotion())) : null;
|
||||
+ // Paper end
|
||||
|
||||
if (list != null) {
|
||||
Iterator iterator = list.iterator();
|
Loading…
Add table
Add a link
Reference in a new issue