More more more more more work

This commit is contained in:
Nassim Jahnke 2023-06-07 21:54:11 +02:00
parent 94aa4b518a
commit 3fed7289ed
No known key found for this signature in database
GPG key ID: 6BE3B555EBC5982B
39 changed files with 124 additions and 125 deletions

View file

@ -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 07b2d28c5cba543b104ade6a180b0940a794e08c..b1a9c75081f7e61212ea9395b35375e067fd7fc6 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -117,6 +117,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) {
@@ -317,7 +318,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) {

View file

@ -1,241 +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..5d7110a33957a597592cacb864c947eb053e8563
--- /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.server.motd(), 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..6b0bdc266109cdfb874f08bf74323603921d2260
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
@@ -0,0 +1,116 @@
+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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import javax.annotation.Nonnull;
+import net.minecraft.network.Connection;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
+import net.minecraft.network.protocol.status.ServerStatus;
+import net.minecraft.server.MinecraftServer;
+import org.bukkit.craftbukkit.util.CraftIconCache;
+
+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 List<GameProfile> originalSample;
+
+ private StandardPaperServerListPingEventImpl(MinecraftServer server, Connection networkManager, ServerStatus ping) {
+ super(server, new PaperStatusClient(networkManager), ping.version().map(ServerStatus.Version::protocol).orElse(-1), server.server.getServerIcon());
+ this.originalSample = ping.players().map(ServerStatus.Players::sample).orElse(null); // 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 List<GameProfile> getPlayerSampleHandle() {
+ if (this.originalSample != null) {
+ return this.originalSample;
+ }
+
+ List<PlayerProfile> entries = super.getPlayerSample();
+ if (entries.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ final List<GameProfile> profiles = new ArrayList<>();
+ for (PlayerProfile profile : entries) {
+ /*
+ * 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.
+ */
+ if (profile.getId() != null && profile.getName() != null) {
+ profiles.add(CraftPlayerProfile.asAuthlib(profile));
+ } else {
+ profiles.add(new GameProfile(MoreObjects.firstNonNull(profile.getId(), FAKE_UUID), Strings.nullToEmpty(profile.getName())));
+ }
+ }
+ return profiles;
+ }
+
+ 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
+
+ // Description
+ final Component description = new AdventureComponent(event.motd());
+
+ // Players
+ final Optional<ServerStatus.Players> players;
+ if (!event.shouldHidePlayers()) {
+ players = Optional.of(new ServerStatus.Players(event.getMaxPlayers(), event.getNumPlayers(), event.getPlayerSampleHandle()));
+ } else {
+ players = Optional.empty();
+ }
+
+ // Version
+ final ServerStatus.Version version = new ServerStatus.Version(event.getVersion(), event.getProtocolVersion());
+
+ // Favicon
+ final Optional<ServerStatus.Favicon> favicon;
+ if (event.getServerIcon() != null) {
+ favicon = Optional.of(new ServerStatus.Favicon(((CraftIconCache) event.getServerIcon()).value));
+ } else {
+ favicon = Optional.empty();
+ }
+ final ServerStatus ping = new ServerStatus(description, players, Optional.of(version), favicon, server.enforceSecureProfile());
+
+ // Send response
+ networkManager.send(new ClientboundStatusResponsePacket(ping));
+ }
+
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 4e263a0ca438ffd1253cda577689a1b6d2d55992..274f3a213e60c9b67dbc43c8b53efb676b8bd41e 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -3,6 +3,9 @@ package net.minecraft.server;
import com.google.common.base.Preconditions;
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;
@@ -1349,7 +1352,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (this.hidesOnlinePlayers()) {
return new ServerStatus.Players(i, list.size(), List.of());
} else {
- int j = Math.min(list.size(), 12);
+ int j = Math.min(list.size(), org.spigotmc.SpigotConfig.playerSample); // Paper
ObjectArrayList<GameProfile> objectarraylist = new ObjectArrayList(j);
int k = Mth.nextInt(this.random, 0, list.size() - j);
diff --git a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
index d99b2235038eb1aba8cda474c4aa51e207149ef4..2c13147bc063a09bb7907d6f90c3a1e811a09eb1 100644
--- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
@@ -48,6 +48,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.status));
MinecraftServer server = MinecraftServer.getServer();
@@ -150,6 +152,9 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
this.connection.send(new ClientboundStatusResponsePacket(ping));
// CraftBukkit end
+ */
+ com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(MinecraftServer.getServer(), this.connection);
+ // Paper end
}
}
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
index 489ce6f439778b26eb33ede9432681d4bf9e0116..ddc5f2d9aa7dda6aff132392927e3d7e3674dbff 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
}

View file

@ -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 9607c3297c1a977cb33fb730eacb35ce9604b74c..6b31b0894e52ad6fc397624e50587ec04e46c099 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -329,8 +329,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);

View file

@ -1,200 +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.
== AT ==
public-f net.minecraft.world.entity.player.Player gameProfile
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index efc9b3bf0a63f87f8d1cab57b8f521a306aef5f3..d9c441f600a1f981a9dad075cba9d1d9b28e1aa0 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1536,7 +1536,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
this.internalTeleport(dest.getX(), dest.getY(), dest.getZ(), dest.getYaw(), dest.getPitch(), Collections.emptySet());
}
- private void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<RelativeMovement> set) {
+ public void internalTeleport(double d0, double d1, double d2, float f, float f1, Set<RelativeMovement> set) { // Paper
// CraftBukkit start
if (Float.isNaN(f)) {
f = 0;
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 6b31b0894e52ad6fc397624e50587ec04e46c099..0c7f280bae81bbb492d5780a43e5ffda0f58756a 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -330,11 +330,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/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
index e7442952ef1f03969949014492a7ddc6d0796ba5..69a1852905dd4724c30ac8ab88c14251eee2c371 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
@@ -76,8 +76,8 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
}
@Override
- public PlayerProfile getPlayerProfile() {
- return new CraftPlayerProfile(this.profile);
+ public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() { // Paper
+ return new com.destroystokyo.paper.profile.CraftPlayerProfile(this.profile); // Paper
}
public Server getServer() {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 6ec434b6e07aba63b28f9f03eadc3550e43f9998..d3b5c7d0d6ac449ecfb99e0ed62981b296528e07 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -82,6 +82,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;
@@ -291,11 +292,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;
@@ -1686,8 +1682,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
private void untrackAndHideEntity(org.bukkit.entity.Entity entity) {
// 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());
@@ -1700,8 +1703,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
this.getHandle().connection.send(new ClientboundPlayerInfoRemovePacket(List.of(otherPlayer.getUUID())));
}
}
-
- server.getPluginManager().callEvent(new PlayerHideEntityEvent(this, entity));
}
void resetAndHideEntity(org.bukkit.entity.Entity entity) {
@@ -1778,8 +1779,38 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
if (entry != null && !entry.seenBy.contains(this.getHandle().connection)) {
entry.updatePlayer(this.getHandle());
}
+ server.getPluginManager().callEvent(new PlayerShowEntityEvent(this, entity)); // Paper
+ }
+ // Paper start
+ @Override
+ public void setPlayerProfile(com.destroystokyo.paper.profile.PlayerProfile profile) {
+ ServerPlayer self = this.getHandle();
+ GameProfile gameProfile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
+ if (!self.sentListPacket) {
+ self.gameProfile = gameProfile;
+ return;
+ }
+ List<ServerPlayer> players = this.server.getServer().getPlayerList().players;
+ // First unregister the player for all players with the OLD game profile
+ for (ServerPlayer player : players) {
+ CraftPlayer bukkitPlayer = player.getBukkitEntity();
+ if (bukkitPlayer.canSee(this)) {
+ bukkitPlayer.unregisterEntity(self);
+ }
+ }
+
+ // Set the game profile here, we should have unregistered the entity via iterating all player entities above.
+ self.gameProfile = gameProfile;
- server.getPluginManager().callEvent(new PlayerShowEntityEvent(this, entity));
+ // Re-register the game profile for all players
+ for (ServerPlayer player : players) {
+ CraftPlayer bukkitPlayer = player.getBukkitEntity();
+ if (bukkitPlayer.canSee(this)) {
+ bukkitPlayer.trackAndShowEntity(self.getBukkitEntity());
+ }
+ }
+ // Refresh misc player things AFTER sending game profile
+ this.refreshPlayer();
}
void resetAndShowEntity(org.bukkit.entity.Entity entity) {
@@ -1792,6 +1823,36 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
this.trackAndShowEntity(entity);
}
}
+ // Paper start
+ public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() {
+ return new com.destroystokyo.paper.profile.CraftPlayerProfile(this).clone();
+ }
+
+ private void refreshPlayer() {
+ ServerPlayer handle = this.getHandle();
+ Location loc = this.getLocation();
+
+ ServerGamePacketListenerImpl connection = handle.connection;
+
+ //Respawn the player then update their position and selected slot
+ ServerLevel worldserver = handle.getLevel();
+ connection.send(new net.minecraft.network.protocol.game.ClientboundRespawnPacket(worldserver.dimensionTypeId(), worldserver.dimension(), net.minecraft.world.level.biome.BiomeManager.obfuscateSeed(worldserver.getSeed()), handle.gameMode.getGameModeForPlayer(), handle.gameMode.getPreviousGameModeForPlayer(), worldserver.isDebug(), worldserver.isFlat(), net.minecraft.network.protocol.game.ClientboundRespawnPacket.KEEP_ALL_DATA, this.getHandle().getLastDeathLocation()));
+ handle.onUpdateAbilities();
+ connection.internalTeleport(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch(), java.util.Collections.emptySet());
+ net.minecraft.server.MinecraftServer.getServer().getPlayerList().sendAllPlayerInfo(handle);
+
+ // Resend their XP and effects because the respawn packet resets it
+ connection.send(new net.minecraft.network.protocol.game.ClientboundSetExperiencePacket(handle.experienceProgress, handle.totalExperience, handle.experienceLevel));
+ for (net.minecraft.world.effect.MobEffectInstance mobEffect : handle.getActiveEffects()) {
+ connection.send(new net.minecraft.network.protocol.game.ClientboundUpdateMobEffectPacket(handle.getId(), mobEffect));
+ }
+
+ if (this.isOp()) {
+ this.setOp(false);
+ this.setOp(true);
+ }
+ }
+ // Paper end
public void onEntityRemove(Entity entity) {
this.invertedVisibilityEntities.remove(entity.getUUID());
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
index 173a2832f029e3d568208a1b56419c1b8501483c..48cdd483c25825571043800f3cfa41a4d723f649 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/Commodore.java
@@ -329,6 +329,12 @@ public class Commodore
return;
}
+ // Paper start - Rewrite plugins
+ if ((owner.equals("org/bukkit/OfflinePlayer") || owner.equals("org/bukkit/entity/Player")) && name.equals("getPlayerProfile") && desc.equals("()Lorg/bukkit/profile/PlayerProfile;")) {
+ super.visitMethodInsn(opcode, owner, name, "()Lcom/destroystokyo/paper/profile/PlayerProfile;", itf);
+ return;
+ }
+ // Paper end
if ( modern )
{
if ( owner.equals( "org/bukkit/Material" ) )

View file

@ -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 5dcbb06370cdf6a5f700ebd09a9a765c9587a688..cb70820fd96624c2378e98d48ac31a11dc9e25e3 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1740,6 +1740,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 (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.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) {

View file

@ -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) {

View file

@ -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 5518a0efb65190732c88ca18a0bdf35316b8687c..d3311d1d4a5f7535f07116865ef0701d82bcbcbd 100644
--- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
+++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
@@ -17,6 +17,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;
@@ -25,6 +26,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;
@@ -55,6 +66,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;
@@ -78,6 +93,7 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
} finally {
bytebuf1.release();
}
+ */ // Paper end - Replace with improved version below
}
bytebuf.release();
@@ -95,6 +111,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);
}

View file

@ -1,150 +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..cc54b1c207981235b5160e8773b27cf9a5dcd4d5
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/network/PaperLegacyStatusClient.java
@@ -0,0 +1,75 @@
+package com.destroystokyo.paper.network;
+
+import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
+import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
+import net.minecraft.ChatFormatting;
+import net.minecraft.server.MinecraftServer;
+import org.apache.commons.lang3.StringUtils;
+
+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;
+ }
+
+ @SuppressWarnings("deprecation") // Valid as this is the legacy status client
+ 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(PlainTextComponentSerializer.plainText().serialize(event.motd()), ChatFormatting.PREFIX_CODE));
+ }
+
+ 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 d3311d1d4a5f7535f07116865ef0701d82bcbcbd..21393ad40095a4049e5b6871169b2db7aa92d13c 100644
--- a/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
+++ b/src/main/java/net/minecraft/server/network/LegacyQueryHandler.java
@@ -48,13 +48,21 @@ 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(Locale.ROOT, "%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(Locale.ROOT, "%s\u00a7%d\u00a7%d", com.destroystokyo.paper.network.PaperLegacyStatusClient.getUnformattedMotd(event), event.getNumPlayers(), event.getMaxPlayers());
this.sendFlushAndClose(channelhandlercontext, this.createReply(s));
+ // Paper end
break;
case 1:
if (bytebuf.readUnsignedByte() != 1) {
@@ -62,7 +70,14 @@ public class LegacyQueryHandler extends ChannelInboundHandlerAdapter {
}
LegacyQueryHandler.LOGGER.debug("Ping: (1.4-1.5.x) from {}:{}", inetsocketaddress.getAddress(), inetsocketaddress.getPort());
- s = String.format(Locale.ROOT, "\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(Locale.ROOT, "\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:
@@ -172,8 +187,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));
}

View file

@ -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 d3b5c7d0d6ac449ecfb99e0ed62981b296528e07..e65981b8d064c6f9309b7b574531a6083fe0d783 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -182,6 +182,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) {
@@ -2061,7 +2062,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));

View file

@ -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 46b18cac2c40db01ebd29528d529fe631b03ddbb..f399a69e9dbac06e591219040634cbdb9382d3a2 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
@@ -100,15 +100,15 @@ public class CraftSign<T extends SignBlockEntity> extends CraftBlockEntityState<
super.applyTo(sign);
}
- 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 03a05d4d34181b34ca67bdbd6c66006071bdcdb4..04fe1bd9254b084eacbbca0e2a8a1ac100d17f12 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
@@ -628,6 +628,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;

View file

@ -1,24 +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/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index ad723fc78d7fc57c67b5a74bb7dd2fd6623d18dd..f92a5fc15b05b247dd62ccfdf690c2ef2b702b65 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -1289,7 +1289,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().misc.disableSprintInterruptionOnAttack) {
+ this.setSprinting(false);
+ }
+ // Paper end
}
if (flag3) {

View file

@ -1,58 +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 d5f6769a50dee22349713bd313858c799a5a3960..167be7bc35f83fb3563044492195181c75b0bd1d 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
@@ -118,6 +118,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)) {
@@ -272,7 +278,7 @@ public class EnderMan extends Monster implements NeutralMob {
if (this.level.isDay() && this.tickCount >= this.targetChangeTime + 600) {
float f = this.getLightLevelDependentMagicValue();
- 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();
}
@@ -398,11 +404,13 @@ public class EnderMan extends Monster implements NeutralMob {
} else {
flag1 = flag && this.hurtWithCleanWater(source, (ThrownPotion) source.getDirectEntity(), amount);
+ 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 flag1;
}
@@ -633,7 +641,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();
}

View file

@ -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 167be7bc35f83fb3563044492195181c75b0bd1d..54088f183e218e10d48e07f3f66b2fdb892a1035 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
@@ -287,7 +287,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();

View file

@ -1,46 +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.
== AT ==
public net.minecraft.world.entity.projectile.Projectile cachedOwner
public net.minecraft.world.entity.projectile.Projectile ownerUUID
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 343e6da38413ab8dad876884241ad31172466659..d273673978c8270f2e0719412372039406e31f5e 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2178,6 +2178,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().fixes.disableUnloadedChunkEnderpearlExploit && 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 f5ce2653489e544ca95cae9cfb1f209dd047824c..ad5c96e9a7577df1729533ec9a709387b7232844 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
@@ -91,6 +91,7 @@ public abstract class Projectile extends Entity implements TraceableEntity {
protected void readAdditionalSaveData(CompoundTag nbt) {
if (nbt.hasUUID("Owner")) {
this.ownerUUID = nbt.getUUID("Owner");
+ if (this instanceof ThrownEnderpearl && this.level != null && this.level.paperConfig().fixes.disableUnloadedChunkEnderpearlExploit) { this.ownerUUID = null; } // Paper - Don't store shooter name for pearls to block enderpearl travel exploit
}
this.leftOwner = nbt.getBoolean("LeftOwner");

View file

@ -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 d273673978c8270f2e0719412372039406e31f5e..65110445ff8a245742c4f7a7055f544ff6344f75 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1576,12 +1576,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 632cc1e185b61677d42405d212f41833ee1bc9d4..33cd9cb5b048fccd6bf7720aa1249f966f5b1e6d 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1856,11 +1856,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

View file

@ -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 331b642c36af97f7f05bd63f96d42d1af443e5a3..a3af96b2518b41f370d09cfda26dc589b9ee977b 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().environment.frostedIce.delay.min, world.paperConfig().environment.frostedIce.delay.max)); // 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;

View file

@ -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 54088f183e218e10d48e07f3f66b2fdb892a1035..908ef284f17296c72009a5803dfefff13664fb1c 100644
--- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
+++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java
@@ -230,7 +230,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())) {

View file

@ -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 e8be8054c3d54defe5e42e2c8a48e2b69552cd9c..b1dc61cd1a3ec4a9e8f0a0b0117ead1f31942c11 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Witch.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java
@@ -124,7 +124,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();

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 16 May 2018 20:44:58 -0400
Subject: [PATCH] WitchThrowPotionEvent
Fired when a witch throws a potion at a player
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 b1dc61cd1a3ec4a9e8f0a0b0117ead1f31942c11..d9608df5227970e31ebc35a8293edb2de1e7ba76 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Witch.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java
@@ -236,9 +236,16 @@ public class Witch extends Raider implements RangedAttackMob {
potionregistry = Potions.WEAKNESS;
}
+ // Paper start
+ ItemStack potion = PotionUtils.setPotion(new ItemStack(Items.SPLASH_POTION), potionregistry);
+ com.destroystokyo.paper.event.entity.WitchThrowPotionEvent event = new com.destroystokyo.paper.event.entity.WitchThrowPotionEvent((org.bukkit.entity.Witch) this.getBukkitEntity(), (org.bukkit.entity.LivingEntity) target.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(potion));
+ if (!event.callEvent()) {
+ return;
+ }
+ potion = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getPotion());
ThrownPotion entitypotion = new ThrownPotion(this.level, this);
-
- entitypotion.setItem(PotionUtils.setPotion(new ItemStack(Items.SPLASH_POTION), potionregistry));
+ entitypotion.setItem(potion);
+ // Paper end
entitypotion.setXRot(entitypotion.getXRot() - -20.0F);
entitypotion.shoot(d0, d1 + d3 * 0.2D, d2, 0.75F, 8.0F);
if (!this.isSilent()) {

View file

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 4 Jun 2018 20:39:20 -0400
Subject: [PATCH] Allow spawning Item entities with World.spawnEntity
This API has more capabilities than .dropItem with the Consumer function
Item can be set inside of the Consumer pre spawn function.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
index 7c5d5355237bc00f1c8c8433351ca7a9938f2e8b..d9be32a5141d7b322f31b61c685ca712cdb45182 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
@@ -593,6 +593,10 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
entity = net.minecraft.world.entity.EntityType.BOAT.create(world);
}
entity.moveTo(x, y, z, yaw, pitch);
+ // Paper start
+ } else if (org.bukkit.entity.Item.class.isAssignableFrom(clazz)) {
+ entity = new net.minecraft.world.entity.item.ItemEntity(world, x, y, z, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Item.byBlock(net.minecraft.world.level.block.Blocks.DIRT)));
+ // Paper end
} else if (FallingBlock.class.isAssignableFrom(clazz)) {
BlockPos pos = BlockPos.containing(x, y, z);
entity = FallingBlockEntity.fall(world, pos, this.getHandle().getBlockState(pos));

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 5 Jun 2018 22:47:26 -0400
Subject: [PATCH] WitchReadyPotionEvent
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 d9608df5227970e31ebc35a8293edb2de1e7ba76..abbb077281eb8fc7961cf97ff23bb9822f2727f0 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Witch.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Witch.java
@@ -157,7 +157,11 @@ public class Witch extends Raider implements RangedAttackMob {
}
if (potionregistry != null) {
- this.setItemSlot(EquipmentSlot.MAINHAND, PotionUtils.setPotion(new ItemStack(Items.POTION), potionregistry));
+ // Paper start
+ ItemStack potion = PotionUtils.setPotion(new ItemStack(Items.POTION), potionregistry);
+ org.bukkit.inventory.ItemStack bukkitStack = com.destroystokyo.paper.event.entity.WitchReadyPotionEvent.process((org.bukkit.entity.Witch) this.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(potion));
+ this.setItemSlot(EquipmentSlot.MAINHAND, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(bukkitStack));
+ // Paper end
this.usingTime = this.getMainHandItem().getUseDuration();
this.setUsingItem(true);
if (!this.isSilent()) {

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 5 Jun 2018 23:00:29 -0400
Subject: [PATCH] ItemStack#getMaxItemUseDuration
Allows you to determine how long it takes to use a usable/consumable item
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index da5e660860a46227c59567f6458a9cf4ac4092eb..3726339bff55bafce9d985254c91241c0c20b4b7 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -173,6 +173,13 @@ public final class CraftItemStack extends ItemStack {
return (this.handle == null) ? Material.AIR.getMaxStackSize() : this.handle.getItem().getMaxStackSize();
}
+ // Paper start
+ @Override
+ public int getMaxItemUseDuration() {
+ return handle == null ? 0 : handle.getUseDuration();
+ }
+ // Paper end
+
@Override
public void addUnsafeEnchantment(Enchantment ench, int level) {
Validate.notNull(ench, "Cannot add null enchantment");

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sat, 9 Jun 2018 14:08:39 +0200
Subject: [PATCH] Implement EntityTeleportEndGatewayEvent
diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
index 5fd074909f18f9b865ac1bcbed3711430e5349b0..757be65a8b6a85be91deeeea895e683eb107e809 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java
@@ -225,9 +225,20 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity {
}
// CraftBukkit end
+ // Paper start - EntityTeleportEndGatewayEvent - replicated from above
+ org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity = entity.getBukkitEntity();
+ org.bukkit.Location location = new org.bukkit.Location(world.getWorld(), (double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.5D, (double) blockposition1.getZ() + 0.5D);
+ location.setPitch(bukkitEntity.getLocation().getPitch());
+ location.setYaw(bukkitEntity.getLocation().getYaw());
+
+ com.destroystokyo.paper.event.entity.EntityTeleportEndGatewayEvent event = new com.destroystokyo.paper.event.entity.EntityTeleportEndGatewayEvent(bukkitEntity, bukkitEntity.getLocation(), location, new org.bukkit.craftbukkit.block.CraftEndGateway(world.getWorld(), blockEntity));
+ if (!event.callEvent()) {
+ return;
+ }
+ // Paper end
entity1.setPortalCooldown();
- entity1.teleportToWithTicket((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY(), (double) blockposition1.getZ() + 0.5D);
+ entity1.teleportToWithTicket(event.getTo().getX(), event.getTo().getY(), event.getTo().getZ()); // Paper
}
TheEndGatewayBlockEntity.triggerCooldown(world, pos, state, blockEntity);

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 10 Jun 2018 01:18:49 -0400
Subject: [PATCH] Unset Ignited flag on cancel of Explosion Event
Otherwise the creeper infinite explodes
diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
index baa30d4bdc8c31d04c84e4992062575709c4f2a4..d34945bc60d2b1734ec65be444ae8745cba2029d 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
@@ -276,6 +276,7 @@ public class Creeper extends Monster implements PowerableMob {
this.spawnLingeringCloud();
} else {
this.swell = 0;
+ this.entityData.set(DATA_IS_IGNITED, Boolean.valueOf(false)); // Paper
}
// CraftBukkit end
}

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 10 Jun 2018 20:20:15 -0400
Subject: [PATCH] Fix CraftEntity hashCode
hashCodes are not allowed to change, however bukkit used a value
that does change, the entityId.
When an entity is teleported dimensions, the entity reference is
replaced with a new one with a new entity ID.
For hashCode, we can simply use the UUID's hashCode to keep
the hashCode from changing.
equals() is ok to use getEntityId() because equals() should only
be true if both the left and right are the same reference.
Since entity ids can not duplicate during runtime, this
check is essentially the same as this.getHandle() == other.getHandle()
However, replaced it too to make it clearer of intent.
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 5a44b9a94992f3703ae1353dbaad40fe25e89a50..dc4060aee09ec9700a9379e0536fd758c3c1eb25 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -837,14 +837,15 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return false;
}
final CraftEntity other = (CraftEntity) obj;
- return (this.getEntityId() == other.getEntityId());
+ return (this.getHandle() == other.getHandle()); // Paper - while logically the same, this is clearer
}
+ // Paper - Fix hashCode. entity ID's are not static.
+ // A CraftEntity can change reference to a new entity with a new ID, and hash codes should never change
@Override
public int hashCode() {
- int hash = 7;
- hash = 29 * hash + this.getEntityId();
- return hash;
+ return getUniqueId().hashCode();
+ // Paper end
}
@Override

View file

@ -1,78 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 15 Jun 2018 00:30:32 -0400
Subject: [PATCH] Configurable Alternative LootPool Luck Formula
Rewrites the Vanilla luck application formula so that luck can be
applied to items that do not have any quality defined.
See: https://luckformula.emc.gs for data and details
-----------
The rough summary is:
My goal was that in a pool, when luck was applied, the pool
rebalances so the percentages for bigger items is
lowered and smaller items is boosted.
Do this by boosting and then reducing the weight value,
so that larger numbers are penalized more than smaller numbers.
resulting in a larger reduction of entries for more common
items than the reduction on small weights,
giving smaller weights more of a chance
-----------
This work kind of obsoletes quality, but quality would be useful
for 2 items with same weight that you want luck to impact
in varying directions.
Fishing still falls into that as the weights are closer, so luck
will invalidate junk more.
This change will result in some major changes to fishing formulas.
-----------
I would love to see this change in Vanilla, so Mojang please pull :)
diff --git a/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java b/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java
index 710a66e9aafe8bd622f9f37789c281aba98d030e..d125b5a470be0f4c56c2c1f229fc5c83fc4d2f3b 100644
--- a/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java
+++ b/src/main/java/net/minecraft/world/level/storage/loot/entries/LootPoolSingletonContainer.java
@@ -113,9 +113,35 @@ public abstract class LootPoolSingletonContainer extends LootPoolEntryContainer
protected abstract class EntryBase implements LootPoolEntry {
@Override
public int getWeight(float luck) {
- return Math.max(Mth.floor((float)LootPoolSingletonContainer.this.weight + (float)LootPoolSingletonContainer.this.quality * luck), 0);
+ // Paper start - Offer an alternative loot formula to refactor how luck bonus applies
+ // SEE: https://luckformula.emc.gs for details and data
+ if (LootPoolSingletonContainer.this.lastLuck != null && LootPoolSingletonContainer.this.lastLuck == luck) {
+ return lastWeight;
+ }
+ // This is vanilla
+ float qualityModifer = (float) LootPoolSingletonContainer.this.quality * luck;
+ double baseWeight = (LootPoolSingletonContainer.this.weight + qualityModifer);
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.useAlternativeLuckFormula) {
+ // Random boost to avoid losing precision in the final int cast on return
+ final int weightBoost = 100;
+ baseWeight *= weightBoost;
+ // If we have vanilla 1, bump that down to 0 so nothing is is impacted
+ // vanilla 3 = 300, 200 basis = impact 2%
+ // =($B2*(($B2-100)/100/100))
+ double impacted = baseWeight * ((baseWeight - weightBoost) / weightBoost / 100);
+ // =($B$7/100)
+ float luckModifier = Math.min(100, luck * 10) / 100;
+ // =B2 - (C2 *($B$7/100))
+ baseWeight = Math.ceil(baseWeight - (impacted * luckModifier));
+ }
+ LootPoolSingletonContainer.this.lastLuck = luck;
+ LootPoolSingletonContainer.this.lastWeight = (int) Math.max(Math.floor(baseWeight), 0);
+ return lastWeight;
}
}
+ private Float lastLuck = null;
+ private int lastWeight = 0;
+ // Paper end
@FunctionalInterface
protected interface EntryConstructor {

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 15 Jun 2018 20:37:03 -0400
Subject: [PATCH] Print Error details when failing to save player data
diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
index 9d25ab52fac9e22d74f874491c7efbcaafa2ffc6..1b076dc77ea57cc779ce3c8742aba2b8c25ce92b 100644
--- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
+++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java
@@ -43,7 +43,7 @@ public class PlayerDataStorage {
Util.safeReplaceFile(file1, file, file2);
} catch (Exception exception) {
- PlayerDataStorage.LOGGER.warn("Failed to save player data for {}", player.getName().getString());
+ PlayerDataStorage.LOGGER.warn("Failed to save player data for {}", player.getScoreboardName(), exception); // Paper
}
}

View file

@ -1,56 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Sat, 16 Jun 2018 01:18:16 -0500
Subject: [PATCH] Make shield blocking delay configurable
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 5ae5f58a6b521318703cf8ba044044992f0ef3f9..059223a014135cd6f6d8fbc4eee7888569fb46b5 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3711,12 +3711,24 @@ public abstract class LivingEntity extends Entity implements Attackable {
if (this.isUsingItem() && !this.useItem.isEmpty()) {
Item item = this.useItem.getItem();
- return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= 5;
+ return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= getShieldBlockingDelay(); // Paper - shieldBlockingDelay
} else {
return false;
}
}
+ // Paper start
+ public int shieldBlockingDelay = level.paperConfig().misc.shieldBlockingDelay;
+
+ public int getShieldBlockingDelay() {
+ return shieldBlockingDelay;
+ }
+
+ public void setShieldBlockingDelay(int shieldBlockingDelay) {
+ this.shieldBlockingDelay = shieldBlockingDelay;
+ }
+ // Paper end
+
public boolean isSuppressingSlidingDownLadder() {
return this.isShiftKeyDown();
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 31f31f0a3dcd5764fffb710111b47359f793b9a2..104be41126252f9cdde3b961f2593b1348a38799 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -791,5 +791,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
public void setArrowsStuck(final int arrows) {
this.getHandle().setArrowCount(arrows);
}
+
+ @Override
+ public int getShieldBlockingDelay() {
+ return getHandle().getShieldBlockingDelay();
+ }
+
+ @Override
+ public void setShieldBlockingDelay(int delay) {
+ getHandle().setShieldBlockingDelay(delay);
+ }
// Paper end
}

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 15 Jun 2013 19:51:17 -0400
Subject: [PATCH] Improve EntityShootBowEvent
Adds missing call to Illagers and also adds Arrow ItemStack to skeletons
== AT ==
public net.minecraft.world.entity.projectile.AbstractArrow getPickupItem()Lnet.minecraft.world.item.ItemStack;
diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
index 1928354a7b9a4e3b03fc355ce7a1c60c23c504a9..362bc2d78e024df5a1cdfad9da6e768e3a778095 100644
--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
@@ -201,7 +201,7 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
entityarrow.shoot(d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float) (14 - this.level.getDifficulty().getId() * 4));
// CraftBukkit start
- org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), null, entityarrow, net.minecraft.world.InteractionHand.MAIN_HAND, 0.8F, true);
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), entityarrow.getPickupItem(), entityarrow, net.minecraft.world.InteractionHand.MAIN_HAND, 0.8F, true); // Paper
if (event.isCancelled()) {
event.getProjectile().remove();
return;
diff --git a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java
index bd65129ec4f1b7c80ef99c34a1d30780f21bb4bf..10573602c9bc73713cbd6989762d3dbb6f6fcf8c 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Illusioner.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Illusioner.java
@@ -196,8 +196,18 @@ public class Illusioner extends SpellcasterIllager implements RangedAttackMob {
double d3 = Math.sqrt(d0 * d0 + d2 * d2);
entityarrow.shoot(d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float) (14 - this.level.getDifficulty().getId() * 4));
+ // Paper start
+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), entityarrow.getPickupItem(), entityarrow, target.getUsedItemHand(), 0.8F, true);
+ if (event.isCancelled()) {
+ event.getProjectile().remove();
+ return;
+ }
+
+ if (event.getProjectile() == entityarrow.getBukkitEntity()) {
+ this.level.addFreshEntity(entityarrow);
+ }
this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F));
- this.level.addFreshEntity(entityarrow);
+ // Paper end
}
@Override

View file

@ -1,44 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 18 Jun 2018 01:12:53 -0400
Subject: [PATCH] PlayerReadyArrowEvent
Called when a player is firing a bow and the server is choosing an arrow to use.
Plugins can skip selection of certain arrows and control which is used.
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 f92a5fc15b05b247dd62ccfdf690c2ef2b702b65..457cafaa39907e85e1d1e9028f0eb75a90f3eb8e 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -2232,18 +2232,29 @@ public abstract class Player extends LivingEntity {
return ImmutableList.of(Pose.STANDING, Pose.CROUCHING, Pose.SWIMMING);
}
+ // Paper start
+ protected boolean tryReadyArrow(ItemStack bow, ItemStack itemstack) {
+ return !(this instanceof ServerPlayer) ||
+ new com.destroystokyo.paper.event.player.PlayerReadyArrowEvent(
+ ((ServerPlayer) this).getBukkitEntity(),
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(bow),
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)
+ ).callEvent();
+ // Paper end
+ }
+
@Override
public ItemStack getProjectile(ItemStack stack) {
if (!(stack.getItem() instanceof ProjectileWeaponItem)) {
return ItemStack.EMPTY;
} else {
- Predicate<ItemStack> predicate = ((ProjectileWeaponItem) stack.getItem()).getSupportedHeldProjectiles();
+ Predicate<ItemStack> predicate = ((ProjectileWeaponItem) stack.getItem()).getSupportedHeldProjectiles().and(item -> tryReadyArrow(stack, item)); // Paper
ItemStack itemstack1 = ProjectileWeaponItem.getHeldProjectile(this, predicate);
if (!itemstack1.isEmpty()) {
return itemstack1;
} else {
- predicate = ((ProjectileWeaponItem) stack.getItem()).getAllSupportedProjectiles();
+ predicate = ((ProjectileWeaponItem) stack.getItem()).getAllSupportedProjectiles().and(item -> tryReadyArrow(stack, item)); // Paper
for (int i = 0; i < this.inventory.getContainerSize(); ++i) {
ItemStack itemstack2 = this.inventory.getItem(i);

View file

@ -1,200 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brokkonaut <hannos17@gmx.de>
Date: Mon, 18 Jun 2018 15:46:23 +0200
Subject: [PATCH] Implement EntityKnockbackByEntityEvent and
EntityPushedByEntityAttackEvent
Co-authored-by: aerulion <aerulion@gmail.com>
This event is called when an entity receives knockback by another entity.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 579b0c70043a545798a6c2871a84c77a5f011744..8b3beb78cf48ea7a23865ddc16c8421ecb047aba 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1775,8 +1775,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
public void push(double deltaX, double deltaY, double deltaZ) {
- this.setDeltaMovement(this.getDeltaMovement().add(deltaX, deltaY, deltaZ));
- this.hasImpulse = true;
+ // Paper start - call EntityPushedByEntityEvent
+ this.push(deltaX, deltaY, deltaZ, null);
+ }
+
+ public void push(double deltaX, double deltaY, double deltaZ, @org.jetbrains.annotations.Nullable Entity pushingEntity) {
+ org.bukkit.util.Vector delta = new org.bukkit.util.Vector(deltaX, deltaY, deltaZ);
+ if (pushingEntity == null || new io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent(getBukkitEntity(), pushingEntity.getBukkitEntity(), delta).callEvent()) {
+ this.setDeltaMovement(this.getDeltaMovement().add(delta.getX(), delta.getY(), delta.getZ()));
+ this.hasImpulse = true;
+ }
+ // Paper end - call EntityPushedByEntityEvent
}
protected void markHurt() {
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index cd0ae977eff36db8a2010596698835dcd9166ef9..10c6f6ac0c56eedf40190216e44d3f5d47b63deb 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1445,7 +1445,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
d0 = (Math.random() - Math.random()) * 0.01D;
}
- this.knockback(0.4000000059604645D, d0, d1);
+ this.knockback(0.4000000059604645D, d0, d1, entity1); // Paper
if (!flag) {
this.indicateDamage(d0, d1);
}
@@ -1494,7 +1494,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
protected void blockedByShield(LivingEntity target) {
- target.knockback(0.5D, target.getX() - this.getX(), target.getZ() - this.getZ());
+ target.knockback(0.5D, target.getX() - this.getX(), target.getZ() - this.getZ(), this); // Paper
}
private boolean checkTotemDeathProtection(DamageSource source) {
@@ -1750,6 +1750,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
public void knockback(double strength, double x, double z) {
+ // Paper start - add knockbacking entity parameter
+ this.knockback(strength, x, z, null);
+ }
+ public void knockback(double strength, double x, double z, Entity knockingBackEntity) {
+ // Paper end - add knockbacking entity parameter
strength *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE);
if (strength > 0.0D) {
this.hasImpulse = true;
@@ -1757,6 +1762,15 @@ public abstract class LivingEntity extends Entity implements Attackable {
Vec3 vec3d1 = (new Vec3(x, 0.0D, z)).normalize().scale(strength);
this.setDeltaMovement(vec3d.x / 2.0D - vec3d1.x, this.onGround ? Math.min(0.4D, vec3d.y / 2.0D + strength) : vec3d.y, vec3d.z / 2.0D - vec3d1.z);
+ // Paper start - call EntityKnockbackByEntityEvent
+ Vec3 currentMovement = this.getDeltaMovement();
+ org.bukkit.util.Vector delta = new org.bukkit.util.Vector(currentMovement.x - vec3d.x, currentMovement.y - vec3d.y, currentMovement.z - vec3d.z);
+ // Restore old velocity to be able to access it in the event
+ this.setDeltaMovement(vec3d);
+ if (knockingBackEntity == null || new com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent((org.bukkit.entity.LivingEntity) getBukkitEntity(), knockingBackEntity.getBukkitEntity(), (float) strength, delta).callEvent()) {
+ this.setDeltaMovement(vec3d.x + delta.getX(), vec3d.y + delta.getY(), vec3d.z + delta.getZ());
+ }
+ // Paper end
}
}
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 6f1755efd7f1cf9dd65d070a3ba7623333f341bc..984a33d5e1f790a9c78ba57f2dc21fb072a44b3d 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -1631,7 +1631,7 @@ public abstract class Mob extends LivingEntity implements Targeting {
if (flag) {
if (f1 > 0.0F && target instanceof LivingEntity) {
- ((LivingEntity) target).knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)));
+ ((LivingEntity) target).knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this); // Paper
this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D));
}
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/RamTarget.java b/src/main/java/net/minecraft/world/entity/ai/behavior/RamTarget.java
index e319a46a21a94314c5d496820b1ac4879dcf56b9..4a3bcd988cf63452c4277ad55ba604ad43c8a623 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/RamTarget.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/RamTarget.java
@@ -77,7 +77,7 @@ public class RamTarget extends Behavior<Goat> {
float f = 0.25F * (float)(i - j);
float g = Mth.clamp(entity.getSpeed() * 1.65F, 0.2F, 3.0F) + f;
float h = livingEntity.isDamageSourceBlocked(world.damageSources().mobAttack(entity)) ? 0.5F : 1.0F;
- livingEntity.knockback((double)(h * g) * this.getKnockbackForce.applyAsDouble(entity), this.ramDirection.x(), this.ramDirection.z());
+ livingEntity.knockback((double)(h * g) * this.getKnockbackForce.applyAsDouble(entity), this.ramDirection.x(), this.ramDirection.z(), entity); // Paper
this.finishRam(world, entity);
world.playSound((Player)null, entity, this.getImpactSound.apply(entity), SoundSource.NEUTRAL, 1.0F, 1.0F);
} else if (this.hasRammedHornBreakingBlock(world, entity)) {
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java b/src/main/java/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java
index 29cfd065f246bbd3d3c2a5bbd32c3f4813a02951..03ec02f9a2fb5abb5387cd0d83c9481d6cbb0bd2 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/warden/SonicBoom.java
@@ -68,7 +68,7 @@ public class SonicBoom extends Behavior<Warden> {
target.hurt(world.damageSources().sonicBoom(entity), 10.0F);
double d = 0.5D * (1.0D - target.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE));
double e = 2.5D * (1.0D - target.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE));
- target.push(vec33.x() * e, vec33.y() * d, vec33.z() * e);
+ target.push(vec33.x() * e, vec33.y() * d, vec33.z() * e, entity); // Paper
});
}
}
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
index 18a9050158f71245d5d88f9c0833fd5d4e5fdca6..55a8ab31a26a16adbe78b3b34366dc81851c02d4 100644
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
@@ -434,7 +434,7 @@ public class EnderDragon extends Mob implements Enemy {
double d3 = entity.getZ() - d1;
double d4 = Math.max(d2 * d2 + d3 * d3, 0.1D);
- entity.push(d2 / d4 * 4.0D, 0.20000000298023224D, d3 / d4 * 4.0D);
+ entity.push(d2 / d4 * 4.0D, 0.20000000298023224D, d3 / d4 * 4.0D, this); // Paper
if (!this.phaseManager.getCurrentPhase().isSitting() && ((LivingEntity) entity).getLastHurtByMobTimestamp() < entity.tickCount - 2) {
entity.hurt(this.damageSources().mobAttack(this), 5.0F);
this.doEnchantDamageEffects(this, entity);
diff --git a/src/main/java/net/minecraft/world/entity/monster/Ravager.java b/src/main/java/net/minecraft/world/entity/monster/Ravager.java
index f4aa2be477da34c37660f0f3d7997928d327545d..24dc43c7806e99be6dc37af48ec056a5edd19947 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Ravager.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Ravager.java
@@ -274,7 +274,7 @@ public class Ravager extends Raider {
double d1 = entity.getZ() - this.getZ();
double d2 = Math.max(d0 * d0 + d1 * d1, 0.001D);
- entity.push(d0 / d2 * 4.0D, 0.2D, d1 / d2 * 4.0D);
+ entity.push(d0 / d2 * 4.0D, 0.2D, d1 / d2 * 4.0D, this); // Paper
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/monster/hoglin/HoglinBase.java b/src/main/java/net/minecraft/world/entity/monster/hoglin/HoglinBase.java
index f8ccf0cf421bf2d8d6d6ccf8dd9e7c27eb9024ed..de73183166962d84b3fcbb408e011bc9e8486374 100644
--- a/src/main/java/net/minecraft/world/entity/monster/hoglin/HoglinBase.java
+++ b/src/main/java/net/minecraft/world/entity/monster/hoglin/HoglinBase.java
@@ -40,7 +40,7 @@ public interface HoglinBase {
double j = f * (double)(attacker.level.random.nextFloat() * 0.5F + 0.2F);
Vec3 vec3 = (new Vec3(g, 0.0D, h)).normalize().scale(j).yRot(i);
double k = f * (double)attacker.level.random.nextFloat() * 0.5D;
- target.push(vec3.x, k, vec3.z);
+ target.push(vec3.x, k, vec3.z, attacker); // Paper
target.hurtMarked = true;
}
}
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 457cafaa39907e85e1d1e9028f0eb75a90f3eb8e..2961e08fc315a0d5f3b95de9d127948da07e66c8 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -1283,9 +1283,9 @@ public abstract class Player extends LivingEntity {
if (flag5) {
if (i > 0) {
if (target instanceof LivingEntity) {
- ((LivingEntity) target).knockback((double) ((float) i * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)));
+ ((LivingEntity) target).knockback((double) ((float) i * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this); // Paper
} else {
- target.push((double) (-Mth.sin(this.getYRot() * 0.017453292F) * (float) i * 0.5F), 0.1D, (double) (Mth.cos(this.getYRot() * 0.017453292F) * (float) i * 0.5F));
+ target.push((double) (-Mth.sin(this.getYRot() * 0.017453292F) * (float) i * 0.5F), 0.1D, (double) (Mth.cos(this.getYRot() * 0.017453292F) * (float) i * 0.5F), this); // Paper
}
this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D));
@@ -1307,7 +1307,7 @@ public abstract class Player extends LivingEntity {
if (entityliving != this && entityliving != target && !this.isAlliedTo((Entity) entityliving) && (!(entityliving instanceof ArmorStand) || !((ArmorStand) entityliving).isMarker()) && this.distanceToSqr((Entity) entityliving) < 9.0D) {
// CraftBukkit start - Only apply knockback if the damage hits
if (entityliving.hurt(this.damageSources().playerAttack(this).sweep(), f4)) {
- entityliving.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)));
+ entityliving.knockback(0.4000000059604645D, (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this); // Pa
}
// CraftBukkit end
}
diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
index aabb5ad09dd7b11a7dfbaa0849726541c0401951..01ccd4f90ad8aed84a89630cf6df9f7ba9bc3fec 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
@@ -401,7 +401,7 @@ public abstract class AbstractArrow extends Projectile {
Vec3 vec3d = this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D).normalize().scale((double) this.knockback * 0.6D * d0);
if (vec3d.lengthSqr() > 0.0D) {
- entityliving.push(vec3d.x, 0.1D, vec3d.z);
+ entityliving.push(vec3d.x, 0.1D, vec3d.z, this); // Paper
}
}

View file

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 20 Jun 2018 23:17:24 -0400
Subject: [PATCH] Expand Explosions API
Add Entity as a Source capability, and add more API choices, and on Location.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 33cd9cb5b048fccd6bf7720aa1249f966f5b1e6d..076a97209d9ac90bb89970a6d3a6075c022bd2ef 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -711,6 +711,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source) {
return !this.world.explode(source == null ? null : ((CraftEntity) source).getHandle(), x, y, z, power, setFire, breakBlocks ? net.minecraft.world.level.Level.ExplosionInteraction.MOB : net.minecraft.world.level.Level.ExplosionInteraction.NONE).wasCanceled;
}
+ // Paper start
+ @Override
+ public boolean createExplosion(Entity source, Location loc, float power, boolean setFire, boolean breakBlocks) {
+ return !world.explode(source != null ? ((org.bukkit.craftbukkit.entity.CraftEntity) source).getHandle() : null, loc.getX(), loc.getY(), loc.getZ(), power, setFire, breakBlocks ? net.minecraft.world.level.Level.ExplosionInteraction.MOB : net.minecraft.world.level.Level.ExplosionInteraction.NONE).wasCanceled;
+ }
+ // Paper end
@Override
public boolean createExplosion(Location loc, float power) {

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 29 Jun 2018 00:21:28 -0400
Subject: [PATCH] LivingEntity Hand Raised/Item Use API
How long an entity has raised hands to charge an attack or use an item
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 104be41126252f9cdde3b961f2593b1348a38799..a9642e95cde4dc1c3cb9da50c921171c47665536 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -801,5 +801,30 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
public void setShieldBlockingDelay(int delay) {
getHandle().setShieldBlockingDelay(delay);
}
+
+ @Override
+ public ItemStack getActiveItem() {
+ return getHandle().getUseItem().asBukkitMirror();
+ }
+
+ @Override
+ public int getItemUseRemainingTime() {
+ return getHandle().getUseItemRemainingTicks();
+ }
+
+ @Override
+ public int getHandRaisedTime() {
+ return getHandle().getTicksUsingItem();
+ }
+
+ @Override
+ public boolean isHandRaised() {
+ return getHandle().isUsingItem();
+ }
+
+ @Override
+ public org.bukkit.inventory.EquipmentSlot getHandRaised() {
+ return getHandle().getUsedItemHand() == net.minecraft.world.InteractionHand.MAIN_HAND ? org.bukkit.inventory.EquipmentSlot.HAND : org.bukkit.inventory.EquipmentSlot.OFF_HAND;
+ }
// Paper end
}

View file

@ -1,162 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 26 Jun 2018 22:00:49 -0400
Subject: [PATCH] RangedEntity API
Allows you to determine if an entity is capable of ranged attacks,
and to perform an attack.
diff --git a/src/main/java/com/destroystokyo/paper/entity/CraftRangedEntity.java b/src/main/java/com/destroystokyo/paper/entity/CraftRangedEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..d7a8eb1b8f24ed2741ae9dae62d3f6146f273e1d
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/entity/CraftRangedEntity.java
@@ -0,0 +1,20 @@
+package com.destroystokyo.paper.entity;
+
+import net.minecraft.world.entity.Mob;
+import net.minecraft.world.entity.monster.RangedAttackMob;
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
+import org.bukkit.entity.LivingEntity;
+
+public interface CraftRangedEntity<T extends Mob & RangedAttackMob> extends RangedEntity {
+ T getHandle();
+
+ @Override
+ default void rangedAttack(LivingEntity target, float charge) {
+ getHandle().performRangedAttack(((CraftLivingEntity) target).getHandle(), charge);
+ }
+
+ @Override
+ default void setChargingAttack(boolean raiseHands) {
+ getHandle().setAggressive(raiseHands);
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java
index db6ad6eea8fa6f2755bbb0e1325df8bda98e708a..5ff566186431440c25a26900aba14e4adb642031 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractSkeleton.java
@@ -4,7 +4,7 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.AbstractSkeleton;
import org.bukkit.entity.Skeleton;
-public abstract class CraftAbstractSkeleton extends CraftMonster implements AbstractSkeleton {
+public abstract class CraftAbstractSkeleton extends CraftMonster implements AbstractSkeleton, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.monster.AbstractSkeleton> { // Paper
public CraftAbstractSkeleton(CraftServer server, net.minecraft.world.entity.monster.AbstractSkeleton entity) {
super(server, entity);
@@ -14,4 +14,10 @@ public abstract class CraftAbstractSkeleton extends CraftMonster implements Abst
public void setSkeletonType(Skeleton.SkeletonType type) {
throw new UnsupportedOperationException("Not supported.");
}
+ // Paper start
+ @Override
+ public net.minecraft.world.entity.monster.AbstractSkeleton getHandle() {
+ return (net.minecraft.world.entity.monster.AbstractSkeleton) super.getHandle();
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftDrowned.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftDrowned.java
index 34cb8062168258bfd168826ceeb2fde669f6d1a8..03e2acd4829da449a471b0fa1a311e74aee114d3 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftDrowned.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftDrowned.java
@@ -4,7 +4,7 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Drowned;
import org.bukkit.entity.EntityType;
-public class CraftDrowned extends CraftZombie implements Drowned {
+public class CraftDrowned extends CraftZombie implements Drowned, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.monster.Drowned> { // Paper
public CraftDrowned(CraftServer server, net.minecraft.world.entity.monster.Drowned entity) {
super(server, entity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftIllusioner.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftIllusioner.java
index 59b866e54e0d7e1dd8815ffa85275e36271113da..bbf7189a0fc9921e7a6007494f91229d9fba0846 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftIllusioner.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftIllusioner.java
@@ -4,7 +4,7 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Illusioner;
-public class CraftIllusioner extends CraftSpellcaster implements Illusioner {
+public class CraftIllusioner extends CraftSpellcaster implements Illusioner, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.monster.Illusioner> { // Paper
public CraftIllusioner(CraftServer server, net.minecraft.world.entity.monster.Illusioner entity) {
super(server, entity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java
index 92e48f89f8eef4c1110ff6dadea2f436e0b82d21..5500d5768bb22f70b99aa28cf4541b4871e12139 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLlama.java
@@ -9,7 +9,7 @@ import org.bukkit.entity.Llama;
import org.bukkit.entity.Llama.Color;
import org.bukkit.inventory.LlamaInventory;
-public class CraftLlama extends CraftChestedHorse implements Llama {
+public class CraftLlama extends CraftChestedHorse implements Llama, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.animal.horse.Llama> { // Paper
public CraftLlama(CraftServer server, net.minecraft.world.entity.animal.horse.Llama entity) {
super(server, entity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java
index 27763d1eca832abda76c8b3c22595cbaf9b1fe45..aeda5fc001fe4ce55ee467240b275b6050a29f98 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java
@@ -13,7 +13,7 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Piglin;
import org.bukkit.inventory.Inventory;
-public class CraftPiglin extends CraftPiglinAbstract implements Piglin {
+public class CraftPiglin extends CraftPiglinAbstract implements Piglin, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.monster.piglin.Piglin> { // Paper
public CraftPiglin(CraftServer server, net.minecraft.world.entity.monster.piglin.Piglin entity) {
super(server, entity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPillager.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPillager.java
index 06786fba1fef36e8fc3d0f5650160123f728a6d1..beea227855f0b978e655efc298024120df8f4945 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPillager.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPillager.java
@@ -6,7 +6,7 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Pillager;
import org.bukkit.inventory.Inventory;
-public class CraftPillager extends CraftIllager implements Pillager {
+public class CraftPillager extends CraftIllager implements Pillager, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.monster.Pillager> { // Paper
public CraftPillager(CraftServer server, net.minecraft.world.entity.monster.Pillager entity) {
super(server, entity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
index 6a82d567d96a42bfea0e38afb4e8de13eb3ad5a2..659e2959c5330e4764ea1edc7f8de9f464f9ff52 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
@@ -5,7 +5,7 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Snowman;
-public class CraftSnowman extends CraftGolem implements Snowman {
+public class CraftSnowman extends CraftGolem implements Snowman, com.destroystokyo.paper.entity.CraftRangedEntity<SnowGolem> { // Paper
public CraftSnowman(CraftServer server, SnowGolem entity) {
super(server, entity);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java
index 5fbb06e28d5c797cfb6859ce7ef05ba00949f690..eada1f0ff10d4c00f82a6f4411fe18b7184e9901 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWitch.java
@@ -4,7 +4,7 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Witch;
-public class CraftWitch extends CraftRaider implements Witch {
+public class CraftWitch extends CraftRaider implements Witch, com.destroystokyo.paper.entity.CraftRangedEntity<net.minecraft.world.entity.monster.Witch> { // Paper
public CraftWitch(CraftServer server, net.minecraft.world.entity.monster.Witch entity) {
super(server, entity);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java
index 5f78b7ac2313cb8fe9ce835c0317217810a6b023..e92355fa2042c4cf15354a11b7058cacbe996f0d 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftWither.java
@@ -10,7 +10,7 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Wither;
-public class CraftWither extends CraftMonster implements Wither {
+public class CraftWither extends CraftMonster implements Wither, com.destroystokyo.paper.entity.CraftRangedEntity<WitherBoss> { // Paper
private BossBar bossBar;

View file

@ -1,21 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Fri, 22 Jun 2018 10:38:31 -0500
Subject: [PATCH] Add config to disable ender dragon legacy check
diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
index 8412fbcafcfacc907e5dbdfcbde3fdc8a067464d..fd57b5a4cf8906b7bfb7c8c4f57c7b057296c8a3 100644
--- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java
@@ -90,6 +90,10 @@ public class EndDragonFight {
private List<EndCrystal> respawnCrystals;
public EndDragonFight(ServerLevel world, long gatewaysSeed, CompoundTag nbt) {
+ // Paper start
+ this.needsStateScanning = world.paperConfig().entities.spawning.scanForLegacyEnderDragon;
+ if (!this.needsStateScanning) this.dragonKilled = true;
+ // Paper end
this.level = world;
if (nbt.contains("NeedsStateScanning")) {
this.needsStateScanning = nbt.getBoolean("NeedsStateScanning");

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brokkonaut <hannos17@gmx.de>
Date: Tue, 3 Jul 2018 16:08:14 +0200
Subject: [PATCH] Implement World.getEntity(UUID) API
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 076a97209d9ac90bb89970a6d3a6075c022bd2ef..020049ba110ec10d7dfca9117dcc6de190cd6785 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1035,6 +1035,15 @@ public class CraftWorld extends CraftRegionAccessor implements World {
return list;
}
+ // Paper start - getEntity by UUID API
+ @Override
+ public Entity getEntity(UUID uuid) {
+ Validate.notNull(uuid, "UUID cannot be null");
+ net.minecraft.world.entity.Entity entity = world.getEntity(uuid);
+ return entity == null ? null : entity.getBukkitEntity();
+ }
+ // Paper end
+
@Override
public void save() {
org.spigotmc.AsyncCatcher.catchOp("world save"); // Spigot

View file

@ -1,220 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 3 Jul 2018 21:56:23 -0400
Subject: [PATCH] InventoryCloseEvent Reason API
Allows you to determine why an inventory was closed, enabling plugin developers
to "confirm" things based on if it was player triggered close or not.
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 65110445ff8a245742c4f7a7055f544ff6344f75..718a403799246228e085280cb539236b01720d4b 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1308,7 +1308,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
for (net.minecraft.world.level.block.entity.BlockEntity tileentity : chunk.getBlockEntities().values()) {
if (tileentity instanceof net.minecraft.world.Container) {
for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((net.minecraft.world.Container) tileentity).getViewers())) {
- h.closeInventory();
+ h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper
}
}
}
@@ -2268,7 +2268,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
// Spigot Start
if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message
for (org.bukkit.entity.HumanEntity h : Lists.newArrayList(((org.bukkit.inventory.InventoryHolder) entity.getBukkitEntity()).getInventory().getViewers())) {
- h.closeInventory();
+ h.closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); // Paper
}
}
// Spigot End
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 8797bfcf1115fd7011aff9b1d3c0e5ae80aa6d8c..57ab89118811cb0825435b9bdde8f5aeee681d75 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -641,7 +641,7 @@ public class ServerPlayer extends Player {
}
// Paper end
if (!this.level.isClientSide && !this.containerMenu.stillValid(this)) {
- this.closeContainer();
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
this.containerMenu = this.inventoryMenu;
}
@@ -834,7 +834,7 @@ public class ServerPlayer extends Player {
// SPIGOT-943 - only call if they have an inventory open
if (this.containerMenu != this.inventoryMenu) {
- this.closeContainer();
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DEATH); // Paper
}
net.kyori.adventure.text.Component deathMessage = event.deathMessage() != null ? event.deathMessage() : net.kyori.adventure.text.Component.empty(); // Paper - Adventure
@@ -1453,7 +1453,7 @@ public class ServerPlayer extends Player {
}
// CraftBukkit end
if (this.containerMenu != this.inventoryMenu) {
- this.closeContainer();
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.OPEN_NEW); // Paper
}
// this.nextContainerCounter(); // CraftBukkit - moved up
@@ -1481,7 +1481,13 @@ public class ServerPlayer extends Player {
@Override
public void closeContainer() {
- CraftEventFactory.handleInventoryCloseEvent(this); // CraftBukkit
+ // Paper start
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNKNOWN);
+ }
+ @Override
+ public void closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
+ CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit
+ // Paper end
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
this.doCloseContainer();
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index bed9c637d7d26b758ab587eb5cdf2c7f7fb7b356..0f3b223522872aeaacd7f571f60b9f01639820d7 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -220,6 +220,7 @@ import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.inventory.InventoryCloseEvent; // Paper
import org.bukkit.event.inventory.InventoryCreativeEvent;
import org.bukkit.event.inventory.InventoryType.SlotType;
import org.bukkit.event.inventory.SmithItemEvent;
@@ -2680,10 +2681,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
@Override
public void handleContainerClose(ServerboundContainerClosePacket packet) {
+ // Paper start
+ handleContainerClose(packet, InventoryCloseEvent.Reason.PLAYER);
+ }
+ public void handleContainerClose(ServerboundContainerClosePacket packet, InventoryCloseEvent.Reason reason) {
+ // Paper end
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
if (this.player.isImmobile()) return; // CraftBukkit
- CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit
+ CraftEventFactory.handleInventoryCloseEvent(this.player, reason); // CraftBukkit // Paper
this.player.doCloseContainer();
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 39cfbc7e109943878df038b7c3e26c64188104a3..bfc81327f0c64ef3bd2e8ba218f6a4970553a309 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -526,7 +526,7 @@ public abstract class PlayerList {
// CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it
// See SPIGOT-5799, SPIGOT-6145
if (entityplayer.containerMenu != entityplayer.inventoryMenu) {
- entityplayer.closeContainer();
+ entityplayer.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper
}
PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : PaperAdventure.asAdventure(entityplayer.getDisplayName()))); // Paper - Adventure
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 2961e08fc315a0d5f3b95de9d127948da07e66c8..9c12fc197c5367a35acda4155707c602f043e571 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -268,7 +268,7 @@ public abstract class Player extends LivingEntity {
this.updateIsUnderwater();
super.tick();
if (!this.level.isClientSide && this.containerMenu != null && !this.containerMenu.stillValid(this)) {
- this.closeContainer();
+ this.closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.CANT_USE); // Paper
this.containerMenu = this.inventoryMenu;
}
@@ -491,6 +491,13 @@ public abstract class Player extends LivingEntity {
}
+ // Paper start - unused code, but to keep signatures aligned
+ public void closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
+ closeContainer();
+ this.containerMenu = this.inventoryMenu;
+ }
+ // Paper end
+
public void closeContainer() {
this.containerMenu = this.inventoryMenu;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
index 04fe1bd9254b084eacbbca0e2a8a1ac100d17f12..77314674a1f66a514f8f5a0fef5ca188b5af0b6a 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
@@ -378,7 +378,7 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
if (((ServerPlayer) this.getHandle()).connection == null) return;
if (this.getHandle().containerMenu != this.getHandle().inventoryMenu) {
// fire INVENTORY_CLOSE if one already open
- ((ServerPlayer) this.getHandle()).connection.handleContainerClose(new ServerboundContainerClosePacket(this.getHandle().containerMenu.containerId));
+ ((ServerPlayer) this.getHandle()).connection.handleContainerClose(new ServerboundContainerClosePacket(this.getHandle().containerMenu.containerId), org.bukkit.event.inventory.InventoryCloseEvent.Reason.OPEN_NEW); // Paper
}
ServerPlayer player = (ServerPlayer) this.getHandle();
AbstractContainerMenu container;
@@ -448,8 +448,14 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
@Override
public void closeInventory() {
- this.getHandle().closeContainer();
+ // Paper start
+ this.getHandle().closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.PLUGIN);
}
+ @Override
+ public void closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
+ getHandle().closeContainer(reason);
+ }
+ // Paper end
@Override
public boolean isBlocking() {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index e65981b8d064c6f9309b7b574531a6083fe0d783..931ad65bc199a3d5089c9f52d7b8b5d29b115285 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1239,7 +1239,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
// Close any foreign inventory
if (this.getHandle().containerMenu != this.getHandle().inventoryMenu) {
- this.getHandle().closeContainer();
+ this.getHandle().closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason.TELEPORT); // Paper
}
// Check if the fromWorld and toWorld are the same.
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 64ddab11cc8bd9e8063450f2bec22a4277e49414..c50cfe19bd40fb75fc66767d2760eb3b5852c4c8 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1261,7 +1261,7 @@ public class CraftEventFactory {
public static AbstractContainerMenu callInventoryOpenEvent(ServerPlayer player, AbstractContainerMenu container, boolean cancelled) {
if (player.containerMenu != player.inventoryMenu) { // fire INVENTORY_CLOSE if one already open
- player.connection.handleContainerClose(new ServerboundContainerClosePacket(player.containerMenu.containerId));
+ player.connection.handleContainerClose(new ServerboundContainerClosePacket(player.containerMenu.containerId), InventoryCloseEvent.Reason.OPEN_NEW); // Paper
}
CraftServer server = player.level.getCraftServer();
@@ -1435,8 +1435,18 @@ public class CraftEventFactory {
return event;
}
+ // Paper start
+ /**
+ * Incase plugins hooked into this or Spigot adds a new inventory close event. Prefer to pass a reason
+ * @param human
+ */
+ @Deprecated
public static void handleInventoryCloseEvent(net.minecraft.world.entity.player.Player human) {
- InventoryCloseEvent event = new InventoryCloseEvent(human.containerMenu.getBukkitView());
+ handleInventoryCloseEvent(human, org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNKNOWN);
+ }
+ public static void handleInventoryCloseEvent(net.minecraft.world.entity.player.Player human, org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
+ // Paper end
+ InventoryCloseEvent event = new InventoryCloseEvent(human.containerMenu.getBukkitView(), reason); // Paper
human.level.getCraftServer().getPluginManager().callEvent(event);
human.containerMenu.transferTo(human.inventoryMenu, human.getBukkitEntity());
}

View file

@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 4 Jul 2018 15:30:22 -0400
Subject: [PATCH] Vex#get/setSummoner API
Get's the NPC that summoned this Vex and
Allow setting the vex's summoner
Co-authored-by: BillyGalbreath <Blake.Galbreath@GMail.com>
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java
index ba8f9d96029aa26e097abb56963261aa707ef645..50b07045cd17a7576a436c64662ad039d4aa2132 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftVex.java
@@ -19,6 +19,19 @@ public class CraftVex extends CraftMonster implements Vex {
return (net.minecraft.world.entity.monster.Vex) super.getHandle();
}
+ // Paper start
+ @Override
+ public org.bukkit.entity.Mob getSummoner() {
+ net.minecraft.world.entity.Mob owner = getHandle().getOwner();
+ return owner != null ? (org.bukkit.entity.Mob) owner.getBukkitEntity() : null;
+ }
+
+ @Override
+ public void setSummoner(org.bukkit.entity.Mob summoner) {
+ getHandle().setOwner(summoner == null ? null : ((CraftMob) summoner).getHandle());
+ }
+ // Paper end
+
@Override
public String toString() {
return "CraftVex";

View file

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Minecrell <minecrell@minecrell.net>
Date: Fri, 13 Jul 2018 14:54:43 +0200
Subject: [PATCH] Refresh player inventory when cancelling
PlayerInteractEntityEvent
When interacting with entities with an item, the client will assume
the interaction is successful, and update the held item on the
client. However, if the interaction is cancelled on the server side,
the client will still mistakenly remove/replace the item in hand.
Examples for this are milking cows with a bucket or dyeing sheep.
The bucket is replaced with milk and the dye removed from inventory.
Refresh the player inventory when PlayerInteractEntityEvent is
cancelled to avoid this problem.
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 0f3b223522872aeaacd7f571f60b9f01639820d7..c425dc285b6fe42093fb1c8f8fb4d512ec071929 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2562,6 +2562,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
if (event.isCancelled()) {
+ ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); // Paper - Refresh player inventory
return;
}
// CraftBukkit end