more more more work

This commit is contained in:
Noah van der Aa 2023-09-21 22:14:58 +02:00
parent 20253f478f
commit 91671751e7
No known key found for this signature in database
GPG key ID: 547D90BC6FF753CF
50 changed files with 205 additions and 224 deletions

View file

@ -1,80 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 3 Mar 2016 01:17:12 -0600
Subject: [PATCH] Improve Player chat API handling
Properly split up the chat and command handling to reflect the server now
having separate packets for both, and the client always using the correct packet. Text
from a chat packet should never be parsed into a command, even if it starts with the `/`
character.
Add a missing async catcher and improve Spigot's async catcher error message.
== AT ==
public net.minecraft.server.network.ServerGamePacketListenerImpl isChatMessageIllegal(Ljava/lang/String;)Z
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: SoSeDiK <mrsosedik@gmail.com>
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 2c922afde237ca0e56ee6dc067f2989434d4d08c..a4f0cb93a08136888a81f1a8e7ed1d56f92e2195 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2063,7 +2063,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
OutgoingChatMessage outgoing = OutgoingChatMessage.create(original);
- if (!async && s.startsWith("/")) {
+ if (false && !async && s.startsWith("/")) { // Paper - Don't handle commands in chat logic
this.handleCommand(s);
} else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) {
// Do nothing, this is coming from a plugin
@@ -2147,7 +2147,8 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
}
- private void handleCommand(String s) {
+ public void handleCommand(String s) { // Paper - private -> public
+ org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + s); // Paper - Add async catcher
co.aikar.timings.MinecraftTimings.playerCommandTimer.startTiming(); // Paper
if ( org.spigotmc.SpigotConfig.logCommands ) // Spigot
this.LOGGER.info(this.player.getScoreboardName() + " issued server command: " + s);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 66433478fd82f730705fd383b90145d79189a915..fd9457a02f36b0230eb2d4fd549419f46d4b8da3 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -886,7 +886,7 @@ public final class CraftServer implements Server {
public boolean dispatchCommand(CommandSender sender, String commandLine) {
Preconditions.checkArgument(sender != null, "sender cannot be null");
Preconditions.checkArgument(commandLine != null, "commandLine cannot be null");
- org.spigotmc.AsyncCatcher.catchOp("command dispatch"); // Spigot
+ org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + commandLine); // Spigot // Paper - Include command in error message
if (this.commandMap.dispatch(sender, commandLine)) {
return true;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index f5b05eb97f059cfb4d6d22d0a180c5fd8a203f66..a3f85b1cf8b03da90f2461cbe42dd18a630f2255 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -492,7 +492,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
if (this.getHandle().connection == null) return;
- this.getHandle().connection.chat(msg, PlayerChatMessage.system(msg), false);
+ // Paper start - Improve chat handling
+ if (ServerGamePacketListenerImpl.isChatMessageIllegal(msg)) {
+ this.getHandle().connection.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"));
+ } else {
+ if (msg.startsWith("/")) {
+ this.getHandle().connection.handleCommand(msg);
+ } else {
+ final PlayerChatMessage playerChatMessage = PlayerChatMessage.system(msg).withResult(new net.minecraft.network.chat.ChatDecorator.ModernResult(Component.literal(msg), true, false));
+ // TODO chat decorating
+ // TODO text filtering
+ this.getHandle().connection.chat(msg, playerChatMessage, false);
+ }
+ }
+ // Paper end
}
@Override

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: vemacs <d@nkmem.es>
Date: Thu, 3 Mar 2016 01:19:22 -0600
Subject: [PATCH] All chunks are slime spawn chunks toggle
diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java
index 23cb972ca3fde409be0d6517ef8f1c58dab47ff4..476a9b2db5deac803f1cb3c2cbe88b69cc3da8e5 100644
--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java
+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java
@@ -318,7 +318,7 @@ public class Slime extends Mob implements Enemy {
}
ChunkPos chunkcoordintpair = new ChunkPos(pos);
- boolean flag = WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot
+ boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper
if (random.nextInt(10) == 0 && flag && pos.getY() < 40) {
return checkMobSpawnRules(type, world, spawnReason, pos, random);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
index 33677ec811ceab939c419bf7d31b99585e9a1ef1..8ae78690748b2cb5d5186d8859871c1630e10130 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -169,7 +169,7 @@ public class CraftChunk implements Chunk {
@Override
public boolean isSlimeChunk() {
// 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk
- return WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0;
+ return this.worldServer.paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper
}
@Override

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Thu, 3 Mar 2016 02:15:57 -0600
Subject: [PATCH] Expose server CommandMap
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index fd9457a02f36b0230eb2d4fd549419f46d4b8da3..10ef586cbbeae40dbdf01232c416ba132229daa2 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2015,6 +2015,7 @@ public final class CraftServer implements Server {
return this.helpMap;
}
+ @Override // Paper - add override
public SimpleCommandMap getCommandMap() {
return this.commandMap;
}

View file

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Thu, 3 Mar 2016 02:18:39 -0600
Subject: [PATCH] Be a bit more informative in maxHealth exception
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 72ba8335d615fae73f7756003d0379117d2c73e7..b3fcbc3f5f0f8e9ca53fce85a4b86d4c292765df 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -102,7 +102,12 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
@Override
public void setHealth(double health) {
health = (float) health;
- Preconditions.checkArgument(health >= 0 && health <= this.getMaxHealth(), "Health value (%s) must be between 0 and %s", health, this.getMaxHealth());
+ // Paper start - Be more informative
+ Preconditions.checkArgument(health >= 0 && health <= this.getMaxHealth(),
+ "Health value (%s) must be between 0 and %s. (attribute base value: %s%s)",
+ health, this.getMaxHealth(), this.getHandle().getAttribute(Attributes.MAX_HEALTH).getBaseValue(), this instanceof CraftPlayer ? ", player: " + this.getName() : ""
+ );
+ // Paper end
// during world generation, we don't want to run logic for dropping items and xp
if (this.getHandle().generation && health == 0) {

View file

@ -1,176 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Techcable <Techcable@outlook.com>
Date: Thu, 3 Mar 2016 02:32:10 -0600
Subject: [PATCH] Player Tab List and Title APIs
diff --git a/src/main/java/net/minecraft/network/FriendlyByteBuf.java b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
index 9020bc6d9ff6bc0c9b3f00470813f3258554cf45..c2f56f4628e42c130e4c55030432cb43aa0d8458 100644
--- a/src/main/java/net/minecraft/network/FriendlyByteBuf.java
+++ b/src/main/java/net/minecraft/network/FriendlyByteBuf.java
@@ -548,6 +548,11 @@ public class FriendlyByteBuf extends ByteBuf {
public FriendlyByteBuf writeComponent(final net.kyori.adventure.text.Component component) {
return this.writeUtf(PaperAdventure.asJsonString(component, this.adventure$locale), 262144);
}
+
+ @Deprecated
+ public FriendlyByteBuf writeComponent(final net.md_5.bungee.api.chat.BaseComponent[] component) {
+ return this.writeUtf(net.md_5.bungee.chat.ComponentSerializer.toString(component), 262144);
+ }
// Paper end
public FriendlyByteBuf writeComponent(Component text) {
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java
index c44a276d201fdfa5144d45d319d7761583c60639..f68a1a6dc6add9496e25cb52c318e086e356e2bb 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetSubtitleTextPacket.java
@@ -7,6 +7,7 @@ import net.minecraft.network.protocol.Packet;
public class ClientboundSetSubtitleTextPacket implements Packet<ClientGamePacketListener> {
private final Component text;
public net.kyori.adventure.text.Component adventure$text; // Paper
+ public net.md_5.bungee.api.chat.BaseComponent[] components; // Paper
public ClientboundSetSubtitleTextPacket(Component subtitle) {
this.text = subtitle;
@@ -21,6 +22,8 @@ public class ClientboundSetSubtitleTextPacket implements Packet<ClientGamePacket
// Paper start
if (this.adventure$text != null) {
buf.writeComponent(this.adventure$text);
+ } else if (this.components != null) {
+ buf.writeComponent(this.components);
} else
// Paper end
buf.writeComponent(this.text);
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java
index bd808eb312ade7122973a47f4b96505829511da5..bf0f9cab7c66c089f35b851e799ba4a43420b437 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetTitleTextPacket.java
@@ -7,6 +7,7 @@ import net.minecraft.network.protocol.Packet;
public class ClientboundSetTitleTextPacket implements Packet<ClientGamePacketListener> {
private final Component text;
public net.kyori.adventure.text.Component adventure$text; // Paper
+ public net.md_5.bungee.api.chat.BaseComponent[] components; // Paper
public ClientboundSetTitleTextPacket(Component title) {
this.text = title;
@@ -21,6 +22,8 @@ public class ClientboundSetTitleTextPacket implements Packet<ClientGamePacketLis
// Paper start
if (this.adventure$text != null) {
buf.writeComponent(this.adventure$text);
+ } else if (this.components != null) {
+ buf.writeComponent(this.components);
} else
// Paper end
buf.writeComponent(this.text);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index a3f85b1cf8b03da90f2461cbe42dd18a630f2255..7ecf67635dd004b030ee5dde10cd7a9a7f4676cf 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1,5 +1,6 @@
package org.bukkit.craftbukkit.entity;
+import com.destroystokyo.paper.Title;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
@@ -334,6 +335,100 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
}
+ // Paper start
+ @Override
+ public void setPlayerListHeaderFooter(BaseComponent[] header, BaseComponent[] footer) {
+ if (header != null) {
+ String headerJson = net.md_5.bungee.chat.ComponentSerializer.toString(header);
+ playerListHeader = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(headerJson);
+ } else {
+ playerListHeader = null;
+ }
+
+ if (footer != null) {
+ String footerJson = net.md_5.bungee.chat.ComponentSerializer.toString(footer);
+ playerListFooter = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize(footerJson);
+ } else {
+ playerListFooter = null;
+ }
+
+ updatePlayerListHeaderFooter();
+ }
+
+ @Override
+ public void setPlayerListHeaderFooter(BaseComponent header, BaseComponent footer) {
+ this.setPlayerListHeaderFooter(header == null ? null : new BaseComponent[]{header},
+ footer == null ? null : new BaseComponent[]{footer});
+ }
+
+
+ @Override
+ public void setTitleTimes(int fadeInTicks, int stayTicks, int fadeOutTicks) {
+ getHandle().connection.send(new ClientboundSetTitlesAnimationPacket(fadeInTicks, stayTicks, fadeOutTicks));
+ }
+
+ @Override
+ public void setSubtitle(BaseComponent[] subtitle) {
+ final ClientboundSetSubtitleTextPacket packet = new ClientboundSetSubtitleTextPacket((net.minecraft.network.chat.Component) null);
+ packet.components = subtitle;
+ getHandle().connection.send(packet);
+ }
+
+ @Override
+ public void setSubtitle(BaseComponent subtitle) {
+ setSubtitle(new BaseComponent[]{subtitle});
+ }
+
+ @Override
+ public void showTitle(BaseComponent[] title) {
+ final ClientboundSetTitleTextPacket packet = new ClientboundSetTitleTextPacket((net.minecraft.network.chat.Component) null);
+ packet.components = title;
+ getHandle().connection.send(packet);
+ }
+
+ @Override
+ public void showTitle(BaseComponent title) {
+ showTitle(new BaseComponent[]{title});
+ }
+
+ @Override
+ public void showTitle(BaseComponent[] title, BaseComponent[] subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
+ setSubtitle(subtitle);
+ showTitle(title);
+ }
+
+ @Override
+ public void showTitle(BaseComponent title, BaseComponent subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
+ setTitleTimes(fadeInTicks, stayTicks, fadeOutTicks);
+ setSubtitle(subtitle);
+ showTitle(title);
+ }
+
+ @Override
+ public void sendTitle(Title title) {
+ Preconditions.checkNotNull(title, "Title is null");
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
+ setSubtitle(title.getSubtitle() == null ? new BaseComponent[0] : title.getSubtitle());
+ showTitle(title.getTitle());
+ }
+
+ @Override
+ public void updateTitle(Title title) {
+ Preconditions.checkNotNull(title, "Title is null");
+ setTitleTimes(title.getFadeIn(), title.getStay(), title.getFadeOut());
+ if (title.getSubtitle() != null) {
+ setSubtitle(title.getSubtitle());
+ }
+ showTitle(title.getTitle());
+ }
+
+ @Override
+ public void hideTitle() {
+ getHandle().connection.send(new ClientboundClearTitlesPacket(false));
+ }
+ // Paper end
+
@Override
public String getDisplayName() {
if(true) return io.papermc.paper.adventure.DisplayNames.getLegacy(this); // Paper

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 02:46:17 -0600
Subject: [PATCH] Add configurable portal search radius
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 30360e9e8787b893a360ba899d8fac657634de75..b1867fee71b925d6f5d76b0194d68dc2c6277ba0 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -3164,7 +3164,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
double d0 = DimensionType.getTeleportationScale(this.level().dimensionType(), destination.dimensionType());
BlockPos blockposition = worldborder.clampToBounds(this.getX() * d0, this.getY(), this.getZ() * d0);
// CraftBukkit start
- CraftPortalEvent event = this.callPortalEvent(this, destination, new PositionImpl(blockposition.getX(), blockposition.getY(), blockposition.getZ()), PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, flag2 ? 16 : 128, 16);
+ // Paper start
+ int portalSearchRadius = destination.paperConfig().environment.portalSearchRadius;
+ if (level.paperConfig().environment.portalSearchVanillaDimensionScaling && flag2) { // == THE_NETHER
+ portalSearchRadius = (int) (portalSearchRadius / destination.dimensionType().coordinateScale());
+ }
+ // Paper end
+ CraftPortalEvent event = this.callPortalEvent(this, destination, new PositionImpl(blockposition.getX(), blockposition.getY(), blockposition.getZ()), PlayerTeleportEvent.TeleportCause.NETHER_PORTAL, portalSearchRadius, destination.paperConfig().environment.portalCreateRadius); // Paper start - configurable portal radius
if (event == null) {
return null;
}
diff --git a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
index 0762bb248b3bd43a06e89aa1893a6189f0e13866..ed5210c63d964be7c28f59df315766794ec3ea1f 100644
--- a/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
+++ b/src/main/java/net/minecraft/world/level/portal/PortalForcer.java
@@ -43,7 +43,7 @@ public class PortalForcer {
public Optional<BlockUtil.FoundRectangle> findPortalAround(BlockPos pos, boolean destIsNether, WorldBorder worldBorder) {
// CraftBukkit start
- return this.findPortalAround(pos, worldBorder, destIsNether ? 16 : 128); // Search Radius
+ return this.findPortalAround(pos, worldBorder, destIsNether ? level.paperConfig().environment.portalCreateRadius : level.paperConfig().environment.portalSearchRadius); // Search Radius // Paper - search Radius
}
public Optional<BlockUtil.FoundRectangle> findPortalAround(BlockPos blockposition, WorldBorder worldborder, int i) {

View file

@ -1,88 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 02:48:12 -0600
Subject: [PATCH] Add velocity warnings
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 10ef586cbbeae40dbdf01232c416ba132229daa2..c7849bda8cfaa9c6b581f180342687f30da0a639 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -299,6 +299,7 @@ public final class CraftServer implements Server {
public boolean ignoreVanillaPermissions = false;
private final List<CraftPlayer> playerView;
public int reloadCount;
+ public static Exception excessiveVelEx; // Paper - Velocity warnings
static {
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 1ccaf59479dce7b913037f232bb37bdbc75b98a8..5a307e3bf2fc48a74e8c42372f3422fd32224133 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -471,10 +471,40 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
public void setVelocity(Vector velocity) {
Preconditions.checkArgument(velocity != null, "velocity");
velocity.checkFinite();
+ // Paper start - Warn server owners when plugins try to set super high velocities
+ if (!(this instanceof org.bukkit.entity.Projectile || this instanceof org.bukkit.entity.Minecart) && isUnsafeVelocity(velocity)) {
+ CraftServer.excessiveVelEx = new Exception("Excessive velocity set detected: tried to set velocity of entity " + entity.getScoreboardName() + " id #" + getEntityId() + " to (" + velocity.getX() + "," + velocity.getY() + "," + velocity.getZ() + ").");
+ }
+ // Paper end
this.entity.setDeltaMovement(CraftVector.toNMS(velocity));
entity.hurtMarked = true;
}
+ // Paper start
+ /**
+ * Checks if the given velocity is not necessarily safe in all situations.
+ * This function returning true does not mean the velocity is dangerous or to be avoided, only that it may be
+ * a detriment to performance on the server.
+ *
+ * It is not to be used as a hard rule of any sort.
+ * Paper only uses it to warn server owners in watchdog crashes.
+ *
+ * @param vel incoming velocity to check
+ * @return if the velocity has the potential to be a performance detriment
+ */
+ private static boolean isUnsafeVelocity(Vector vel) {
+ final double x = vel.getX();
+ final double y = vel.getY();
+ final double z = vel.getZ();
+
+ if (x > 4 || x < -4 || y > 4 || y < -4 || z > 4 || z < -4) {
+ return true;
+ }
+
+ return false;
+ }
+ // Paper end
+
@Override
public double getHeight() {
return this.getHandle().getBbHeight();
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index 11d7ede26b46d0bf9cced65e8c3bcc41c8b66dbf..3ad14bf0697e682a2e777baa8faeb323d127fb13 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -80,7 +80,19 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
log.log( Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed" );
log.log( Level.SEVERE, "near " + net.minecraft.world.level.Level.lastPhysicsProblem );
}
- //
+ // Paper start - Warn in watchdog if an excessive velocity was ever set
+ if ( org.bukkit.craftbukkit.CraftServer.excessiveVelEx != null )
+ {
+ log.log( Level.SEVERE, "------------------------------" );
+ log.log( Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity" );
+ log.log( Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated" );
+ log.log( Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage());
+ for ( StackTraceElement stack : org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getStackTrace() )
+ {
+ log.log( Level.SEVERE, "\t\t" + stack );
+ }
+ }
+ // Paper end
log.log( Level.SEVERE, "------------------------------" );
log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudzzy <originmc@outlook.com>
Date: Thu, 3 Mar 2016 02:50:31 -0600
Subject: [PATCH] Configurable inter-world teleportation safety
People are able to abuse the way Bukkit handles teleportation across worlds since it provides a built in teleportation
safety check.
To abuse the safety check, players are required to get into a location deemed unsafe by Bukkit e.g. be within a chest
or door block. While they are in this block, they accept a teleport request from a player within a different world. Once
the player teleports, Minecraft will recursively search upwards for a safe location, this could eventually land within a
player's skybase.
Example setup to perform the glitch: http://puu.sh/ng3PC/cf072dcbdb.png
The wanted destination was on top of the emerald block however the player ended on top of the diamond block.
This only is the case if the player is teleporting between worlds.
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 7ecf67635dd004b030ee5dde10cd7a9a7f4676cf..5c91414ca72609a89599baa9fba9774c5923ad10 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1160,7 +1160,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
entity.connection.teleport(to);
} else {
// The respawn reason should never be used if the passed location is non null.
- server.getHandle().respawn(entity, toWorld, true, to, true, null);
+ server.getHandle().respawn(entity, toWorld, true, to, !toWorld.paperConfig().environment.disableTeleportationSuffocationCheck, null); // Paper
}
return true;
}

View file

@ -1,215 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joseph Hirschfeld <joe@ibj.io>
Date: Thu, 3 Mar 2016 03:15:41 -0600
Subject: [PATCH] Add exception reporting event
diff --git a/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..f699ce18ca044f813e194ef2786b7ea853ea86e7
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/ServerSchedulerReportingWrapper.java
@@ -0,0 +1,38 @@
+package com.destroystokyo.paper;
+
+import com.google.common.base.Preconditions;
+import org.bukkit.craftbukkit.scheduler.CraftTask;
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
+import com.destroystokyo.paper.exception.ServerSchedulerException;
+
+/**
+ * Reporting wrapper to catch exceptions not natively
+ */
+public class ServerSchedulerReportingWrapper implements Runnable {
+
+ private final CraftTask internalTask;
+
+ public ServerSchedulerReportingWrapper(CraftTask internalTask) {
+ this.internalTask = Preconditions.checkNotNull(internalTask, "internalTask");
+ }
+
+ @Override
+ public void run() {
+ try {
+ internalTask.run();
+ } catch (RuntimeException e) {
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
+ new ServerExceptionEvent(new ServerSchedulerException(e, internalTask))
+ );
+ throw e;
+ } catch (Throwable t) {
+ internalTask.getOwner().getServer().getPluginManager().callEvent(
+ new ServerExceptionEvent(new ServerSchedulerException(t, internalTask))
+ ); //Do not rethrow, since it is not permitted with Runnable#run
+ }
+ }
+
+ public CraftTask getInternalTask() {
+ return internalTask;
+ }
+}
diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
index 439ff01be1521c283d60cacb110fcb4993933057..da98f074ccd5a40c635824112c97fd174c393cb1 100644
--- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java
+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java
@@ -1,5 +1,6 @@
package net.minecraft.server.players;
+import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
@@ -363,6 +364,7 @@ public class OldUsersConverter {
root = NbtIo.readCompressed(new java.io.FileInputStream(file5));
} catch (Exception exception) {
exception.printStackTrace();
+ ServerInternalException.reportInternalException(exception); // Paper
}
if (root != null) {
@@ -376,6 +378,7 @@ public class OldUsersConverter {
NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
} catch (Exception exception) {
exception.printStackTrace();
+ ServerInternalException.reportInternalException(exception); // Paper
}
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
index c6fb4c33d7ea52b88d8fc0d90748cbab7387c565..fed09b886f4fa0006d160e5f2abb00dfee45434d 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java
@@ -118,6 +118,7 @@ public class VillageSiege implements CustomSpawner {
entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), MobSpawnType.EVENT, (SpawnGroupData) null, (CompoundTag) null);
} catch (Exception exception) {
VillageSiege.LOGGER.warn("Failed to create zombie for village siege at {}", vec3d, exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
return;
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 78041052d7ab2e6b60405ce7e02468458650db22..8149286827d9b609be47a4ded0413ca11f7858de 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -1,5 +1,10 @@
package net.minecraft.world.level;
+import co.aikar.timings.Timing;
+import co.aikar.timings.Timings;
+import com.destroystokyo.paper.event.server.ServerExceptionEvent;
+import com.destroystokyo.paper.exception.ServerInternalException;
+import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import com.mojang.serialization.Codec;
import java.io.IOException;
@@ -730,6 +735,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Paper start - Prevent tile entity and entity crashes
final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ());
MinecraftServer.LOGGER.error(msg, throwable);
+ getCraftServer().getPluginManager().callEvent(new ServerExceptionEvent(new ServerInternalException(msg, throwable)));
entity.discard();
// Paper end
}
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index f1675e35be0ab7670c875c6b0d1e982a3ae09d1e..b2bb9bbd3af414c50ec3f8e3e171a679e95ef75e 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -291,6 +291,7 @@ public final class NaturalSpawner {
NaturalSpawner.LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(type));
} catch (Exception exception) {
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
}
return null;
@@ -404,6 +405,7 @@ public final class NaturalSpawner {
entity = biomesettingsmobs_c.type.create(world.getLevel());
} catch (Exception exception) {
NaturalSpawner.LOGGER.warn("Failed to create mob", exception);
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(exception); // Paper
continue;
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 1f635d06dcff8672e9bdaf29fba6fdf39618f893..36701f196756dc7c6820cac516ff880d00a43b17 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1,6 +1,7 @@
package net.minecraft.world.level.chunk;
import com.google.common.collect.ImmutableList;
+import com.destroystokyo.paper.exception.ServerInternalException;
import com.google.common.collect.Maps;
import com.google.common.collect.UnmodifiableIterator;
import com.mojang.logging.LogUtils;
@@ -568,10 +569,16 @@ public class LevelChunk extends ChunkAccess {
// CraftBukkit start
} else {
- System.out.println("Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + "," + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
- + " (" + this.getBlockState(blockposition) + ") where there was no entity tile!");
- System.out.println("Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16));
- new Exception().printStackTrace();
+ // Paper start
+ ServerInternalException e = new ServerInternalException(
+ "Attempted to place a tile entity (" + blockEntity + ") at " + blockEntity.getBlockPos().getX() + ","
+ + blockEntity.getBlockPos().getY() + "," + blockEntity.getBlockPos().getZ()
+ + " (" + getBlockState(blockposition) + ") where there was no entity tile!\n" +
+ "Chunk coordinates: " + (this.chunkPos.x * 16) + "," + (this.chunkPos.z * 16) +
+ "\nWorld: " + level.getLevel().dimension().location());
+ e.printStackTrace();
+ ServerInternalException.reportInternalException(e);
+ // Paper end
// CraftBukkit end
}
}
@@ -1149,6 +1156,7 @@ public class LevelChunk extends ChunkAccess {
// Paper start - Prevent tile entity and entity crashes
final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ());
net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable);
+ net.minecraft.world.level.chunk.LevelChunk.this.level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new ServerInternalException(msg, throwable)));
LevelChunk.this.removeBlockEntity(this.getPos());
// Paper end
// Spigot start
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index e68205fe7169c7c5b7c6fdada2ee97d86107ca97..aa8972fd1a1fade05d60ab69efb8ff24f344508a 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -275,6 +275,7 @@ public class RegionFile implements AutoCloseable {
return true;
}
} catch (IOException ioexception) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper
return false;
}
}
@@ -356,6 +357,7 @@ public class RegionFile implements AutoCloseable {
((java.nio.Buffer) buf).position(5); // CraftBukkit - decompile error
filechannel.write(buf);
} catch (Throwable throwable) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(throwable); // Paper
if (filechannel != null) {
try {
filechannel.close();
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
index fcbf32a233c240dd45f75ee736bd102ce9f79332..833240d2a4936343710a60876a66d01112e15a2c 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -434,6 +434,8 @@ public class CraftScheduler implements BukkitScheduler {
msg,
throwable);
}
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(
+ new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerSchedulerException(msg, throwable, task)));
// Paper end
} finally {
this.currentTask = null;
@@ -441,7 +443,7 @@ public class CraftScheduler implements BukkitScheduler {
this.parsePending();
} else {
this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass()));
- this.executor.execute(task);
+ this.executor.execute(new com.destroystokyo.paper.ServerSchedulerReportingWrapper(task)); // 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)
}

View file

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Tue, 8 Mar 2016 18:28:43 -0800
Subject: [PATCH] Don't nest if we don't need to when cerealising text
components
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java
index 55e21c7b13826f60e3c656f76e1507e0242e0af3..1387e3597c43fd652f2fc82ca6fc2e83039604e2 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java
@@ -14,7 +14,7 @@ public record ClientboundSystemChatPacket(@javax.annotation.Nullable net.kyori.a
}
public ClientboundSystemChatPacket(net.md_5.bungee.api.chat.BaseComponent[] content, boolean overlay) {
- this(null, net.md_5.bungee.chat.ComponentSerializer.toString(content), overlay); // Paper - Adventure
+ this(null, improveBungeeComponentSerialization(content), overlay); // Paper - Adventure
}
// Spigot end
// Paper start
@@ -25,6 +25,14 @@ public record ClientboundSystemChatPacket(@javax.annotation.Nullable net.kyori.a
public ClientboundSystemChatPacket(net.kyori.adventure.text.Component content, boolean overlay) {
this(content, null, overlay);
}
+
+ private static String improveBungeeComponentSerialization(net.md_5.bungee.api.chat.BaseComponent[] content) {
+ if (content.length == 1) {
+ return net.md_5.bungee.chat.ComponentSerializer.toString(content[0]);
+ } else {
+ return net.md_5.bungee.chat.ComponentSerializer.toString(content);
+ }
+ }
// Paper end
public ClientboundSystemChatPacket(FriendlyByteBuf buf) {

View file

@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 8 Mar 2016 23:25:45 -0500
Subject: [PATCH] Disable Scoreboards for non players by default
Entities collision is checking for scoreboards setting.
This is very heavy to do map lookups for every collision to check
this setting.
So avoid looking up scoreboards and short circuit to the "not on a team"
logic which is most likely to be true.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index b1867fee71b925d6f5d76b0194d68dc2c6277ba0..2d37f4da83282e3430353e01c756a0d952150360 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -2795,6 +2795,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
@Nullable
public Team getTeam() {
+ if (!this.level().paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof Player)) { return null; } // Paper
return this.level().getScoreboard().getPlayersTeam(this.getScoreboardName());
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 5dda05f7bf08dec8b48fe0b87aa227c3e0392c6f..ddf083a54015f943e3e00ae6d5f73f8e127f6dc2 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -833,6 +833,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
if (nbt.contains("Team", 8)) {
String s = nbt.getString("Team");
PlayerTeam scoreboardteam = this.level().getScoreboard().getPlayerTeam(s);
+ if (!this.level().paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof net.minecraft.world.entity.player.Player)) { scoreboardteam = null; } // Paper
boolean flag = scoreboardteam != null && this.level().getScoreboard().addPlayerToTeam(this.getStringUUID(), scoreboardteam);
if (!flag) {

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: mrapple <tony@oc.tc>
Date: Sun, 25 Nov 2012 13:43:39 -0600
Subject: [PATCH] Add methods for working with arrows stuck in living entities
Upstream added methods for this, original methods are now
deprecated
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index b3fcbc3f5f0f8e9ca53fce85a4b86d4c292765df..bba6bce470a11c792bb2edc2171021437e2c9704 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -267,9 +267,15 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
}
@Override
- public void setArrowsInBody(int count) {
+ public void setArrowsInBody(final int count, final boolean fireEvent) { // Paper
Preconditions.checkArgument(count >= 0, "New arrow amount must be >= 0");
+ if (!fireEvent) { // Paper
this.getHandle().getEntityData().set(net.minecraft.world.entity.LivingEntity.DATA_ARROW_COUNT_ID, count);
+ // Paper start
+ } else {
+ this.getHandle().setArrowCount(count);
+ }
+ // Paper end
}
@Override
@@ -783,4 +789,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
this.getHandle().persistentInvisibility = invisible;
this.getHandle().setSharedFlag(5, invisible);
}
+
+ // Paper start
+ @Override
+ public int getArrowsStuck() {
+ return this.getHandle().getArrowCount();
+ }
+
+ @Override
+ public void setArrowsStuck(final int arrows) {
+ this.getHandle().setArrowCount(arrows);
+ }
+ // Paper end
}

View file

@ -1,51 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 4 Mar 2013 23:46:10 -0500
Subject: [PATCH] Chunk Save Reattempt
We commonly have "Stream Closed" errors on chunk saving, so this code should re-try to save the chunk in the event of failure and hopefully prevent rollbacks.
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
index aa8972fd1a1fade05d60ab69efb8ff24f344508a..ddcc212ba83d9365adb842b3d3ced64e3d7dd155 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -275,7 +275,7 @@ public class RegionFile implements AutoCloseable {
return true;
}
} catch (IOException ioexception) {
- com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(ioexception); // Paper
+ com.destroystokyo.paper.util.SneakyThrow.sneaky(ioexception); // Paper - we want the upper try/catch to retry this
return false;
}
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index fe8bb0037bb7f317fc32ac34461f4eb3a1f397f2..a16047cab2709d197489215de66bf24901523a1c 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -208,6 +208,7 @@ public class RegionFileStorage implements AutoCloseable {
}
// Paper end - rewrite chunk system
try { // Paper
+ int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper
if (nbt == null) {
regionfile.clear(pos);
@@ -232,7 +233,18 @@ public class RegionFileStorage implements AutoCloseable {
dataoutputstream.close();
}
}
+ // Paper start
+ return;
+ } catch (Exception ex) {
+ laste = ex;
+ }
+ }
+ if (laste != null) {
+ com.destroystokyo.paper.exception.ServerInternalException.reportInternalException(laste);
+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk " + pos, laste);
+ }
+ // Paper end
} finally { // Paper start
regionfile.fileLock.unlock();
} // Paper end

View file

@ -1,85 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jedediah Smith <jedediah@silencegreys.com>
Date: Sat, 4 Apr 2015 23:17:52 -0400
Subject: [PATCH] Complete resource pack API
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index a4f0cb93a08136888a81f1a8e7ed1d56f92e2195..1c84143d271e70f6ffea301f3e93cd8ed8fd9bd1 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1760,8 +1760,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
ServerGamePacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack rejection", this.player.getName());
this.disconnect(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"));
}
- this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(this.getCraftPlayer(), PlayerResourcePackStatusEvent.Status.values()[packet.action.ordinal()])); // CraftBukkit
-
+ // Paper start
+ PlayerResourcePackStatusEvent.Status packStatus = PlayerResourcePackStatusEvent.Status.values()[packet.action.ordinal()];
+ player.getBukkitEntity().setResourcePackStatus(packStatus);
+ this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(this.getCraftPlayer(), packStatus)); // CraftBukkit
+ // Paper end
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 5c91414ca72609a89599baa9fba9774c5923ad10..038c34e62903afd19fb25b2125d5ed243e081139 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -189,6 +189,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
private double healthScale = 20;
private CraftWorldBorder clientWorldBorder = null;
private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener();
+ // Paper start
+ private org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus;
+ private String resourcePackHash;
+ // Paper end
public CraftPlayer(CraftServer server, ServerPlayer entity) {
super(server, entity);
@@ -2352,6 +2356,45 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
public boolean getAffectsSpawning() {
return this.getHandle().affectsSpawning;
}
+
+ @Override
+ public void setResourcePack(@NotNull String url, @NotNull String hash) {
+ this.setResourcePack(url, hash, false, null);
+ }
+
+ @Override
+ public void setResourcePack(@NotNull String url, @NotNull String hash, boolean required) {
+ this.setResourcePack(url, hash, required, null);
+ }
+
+ @Override
+ public void setResourcePack(@NotNull String url, @NotNull String hash, boolean required, net.kyori.adventure.text.Component resourcePackPrompt) {
+ Preconditions.checkArgument(url != null, "Resource pack URL cannot be null");
+ Preconditions.checkArgument(hash != null, "Hash cannot be null");
+ net.minecraft.network.chat.Component promptComponent = resourcePackPrompt != null ?
+ io.papermc.paper.adventure.PaperAdventure.asVanilla(resourcePackPrompt) :
+ null;
+ this.getHandle().sendTexturePack(url, hash, required, promptComponent);
+ }
+
+ @Override
+ public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status getResourcePackStatus() {
+ return this.resourcePackStatus;
+ }
+
+ @Override
+ public String getResourcePackHash() {
+ return this.resourcePackHash;
+ }
+
+ @Override
+ public boolean hasResourcePack() {
+ return this.resourcePackStatus == org.bukkit.event.player.PlayerResourcePackStatusEvent.Status.SUCCESSFULLY_LOADED;
+ }
+
+ public void setResourcePackStatus(org.bukkit.event.player.PlayerResourcePackStatusEvent.Status status) {
+ this.resourcePackStatus = status;
+ }
// Paper end
@Override

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Mar 2016 13:17:38 -0400
Subject: [PATCH] Default loading permissions.yml before plugins
Under previous behavior, plugins were not able to check if a player had a permission
if it was defined in permissions.yml. there is no clean way for a plugin to fix that either.
This will change the order so that by default, permissions.yml loads BEFORE plugins instead of after.
This gives plugins expected permission checks.
It also helps improve the expected logic, as servers should set the initial defaults, and then let plugins
modify that. Under the previous logic, plugins were unable (cleanly) override permissions.yml.
A config option has been added for those who depend on the previous behavior, but I don't expect that.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index c7849bda8cfaa9c6b581f180342687f30da0a639..6a435ae10003b854d387cfc393b9b526cfcbf0a7 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -462,6 +462,7 @@ public final class CraftServer implements Server {
if (type == PluginLoadOrder.STARTUP) {
this.helpMap.clear();
this.helpMap.initializeGeneralTopics();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions(); // Paper
}
Plugin[] plugins = this.pluginManager.getPlugins();
@@ -481,7 +482,7 @@ public final class CraftServer implements Server {
this.commandMap.registerServerAliases();
DefaultPermissions.registerCorePermissions();
CraftDefaultPermissions.registerCorePermissions();
- this.loadCustomPermissions();
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) this.loadCustomPermissions(); // Paper
this.helpMap.initializeCommands();
this.syncCommands();
}

View file

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William <admin@domnian.com>
Date: Fri, 18 Mar 2016 03:30:17 -0400
Subject: [PATCH] Allow Reloading of Custom Permissions
https://github.com/PaperMC/Paper/issues/49
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 6a435ae10003b854d387cfc393b9b526cfcbf0a7..de50d84008851b44fe8999affbb6c2ac8e376cf3 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2619,5 +2619,23 @@ public final class CraftServer implements Server {
}
return this.adventure$audiences;
}
+
+ @Override
+ public void reloadPermissions() {
+ pluginManager.clearPermissions();
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions();
+ for (Plugin plugin : pluginManager.getPlugins()) {
+ for (Permission perm : plugin.getDescription().getPermissions()) {
+ try {
+ pluginManager.addPermission(perm);
+ } catch (IllegalArgumentException ex) {
+ getLogger().log(Level.WARNING, "Plugin " + plugin.getDescription().getFullName() + " tried to register permission '" + perm.getName() + "' but it's already registered", ex);
+ }
+ }
+ }
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().misc.loadPermissionsYmlBeforePlugins) loadCustomPermissions();
+ DefaultPermissions.registerCorePermissions();
+ CraftDefaultPermissions.registerCorePermissions();
+ }
// Paper end
}

View file

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Mar 2016 13:50:14 -0400
Subject: [PATCH] Remove Metadata on reload
Metadata is not meant to persist reload as things break badly with non primitive types
This will remove metadata on reload so it does not crash everything if a plugin uses it.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index de50d84008851b44fe8999affbb6c2ac8e376cf3..1f294e7841de880ebe99e02265ba28ce8c932d07 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -953,8 +953,16 @@ public final class CraftServer implements Server {
world.spigotConfig.init(); // Spigot
}
+ Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
this.pluginManager.clearPlugins();
this.commandMap.clearCommands();
+ // Paper start
+ for (Plugin plugin : pluginClone) {
+ entityMetadata.removeAll(plugin);
+ worldMetadata.removeAll(plugin);
+ playerMetadata.removeAll(plugin);
+ }
+ // Paper end
this.reloadData();
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper

View file

@ -1,324 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 28 May 2015 23:00:19 -0400
Subject: [PATCH] Handle Item Meta Inconsistencies
First, Enchantment order would blow away seeing 2 items as the same,
however the Client forces enchantment list in a certain order, as well
as does the /enchant command. Anvils can insert it into forced order,
causing 2 same items to be considered different.
This change makes unhandled NBT Tags and Enchantments use a sorted tree map,
so they will always be in a consistent order.
Additionally, the old enchantment API was never updated when ItemMeta
was added, resulting in 2 different ways to modify an items enchantments.
For consistency, the old API methods now forward to use the
ItemMeta API equivalents, and should deprecate the old API's.
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 3f18fb61a47dda559a6997af9c6c043423dd206a..c33660718c0ea281d7bcdb15df0568d4d46547e2 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -156,6 +156,23 @@ public final class ItemStack {
return this.getItem().getTooltipImage(this);
}
+ // Paper start
+ private static final java.util.Comparator<? super CompoundTag> enchantSorter = java.util.Comparator.comparing(o -> o.getString("id"));
+ private void processEnchantOrder(@Nullable CompoundTag tag) {
+ if (tag == null || !tag.contains("Enchantments", 9)) {
+ return;
+ }
+ ListTag list = tag.getList("Enchantments", 10);
+ if (list.size() < 2) {
+ return;
+ }
+ try {
+ //noinspection unchecked
+ list.sort((java.util.Comparator<? super net.minecraft.nbt.Tag>) enchantSorter); // Paper
+ } catch (Exception ignored) {}
+ }
+ // Paper end
+
public ItemStack(ItemLike item) {
this(item, 1);
}
@@ -204,6 +221,7 @@ public final class ItemStack {
// CraftBukkit start - make defensive copy as this data may be coming from the save thread
this.tag = nbttagcompound.getCompound("tag").copy();
// CraftBukkit end
+ this.processEnchantOrder(this.tag); // Paper
this.getItem().verifyTagAfterLoad(this.tag);
}
@@ -814,6 +832,7 @@ public final class ItemStack {
public void setTag(@Nullable CompoundTag nbt) {
this.tag = nbt;
+ this.processEnchantOrder(this.tag); // Paper
if (this.getItem().canBeDepleted()) {
this.setDamageValue(this.getDamageValue());
}
@@ -1111,6 +1130,7 @@ public final class ItemStack {
ListTag nbttaglist = this.tag.getList("Enchantments", 10);
nbttaglist.add(EnchantmentHelper.storeEnchantment(EnchantmentHelper.getEnchantmentId(enchantment), (byte) level));
+ processEnchantOrder(this.tag); // Paper
}
public boolean isEnchanted() {
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index 40aad6a209fbded448e3db21207a85d9f2875e71..4dcbd1ed61070c12adf5871a595875ca60110c5d 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -188,28 +188,11 @@ public final class CraftItemStack extends ItemStack {
public void addUnsafeEnchantment(Enchantment ench, int level) {
Preconditions.checkArgument(ench != null, "Enchantment cannot be null");
- if (!CraftItemStack.makeTag(this.handle)) {
- return;
- }
- ListTag list = CraftItemStack.getEnchantmentList(this.handle);
- if (list == null) {
- list = new ListTag();
- this.handle.getTag().put(ENCHANTMENTS.NBT, list);
- }
- int size = list.size();
-
- for (int i = 0; i < size; i++) {
- CompoundTag tag = (CompoundTag) list.get(i);
- String id = tag.getString(ENCHANTMENTS_ID.NBT);
- if (ench.getKey().equals(NamespacedKey.fromString(id))) {
- tag.putShort(ENCHANTMENTS_LVL.NBT, (short) level);
- return;
- }
- }
- CompoundTag tag = new CompoundTag();
- tag.putString(ENCHANTMENTS_ID.NBT, ench.getKey().toString());
- tag.putShort(ENCHANTMENTS_LVL.NBT, (short) level);
- list.add(tag);
+ // Paper start - Replace whole method
+ final ItemMeta itemMeta = this.getItemMeta();
+ itemMeta.addEnchant(ench, level, true);
+ this.setItemMeta(itemMeta);
+ // Paper end
}
static boolean makeTag(net.minecraft.world.item.ItemStack item) {
@@ -235,57 +218,40 @@ public final class CraftItemStack extends ItemStack {
if (this.handle == null) {
return 0;
}
- return EnchantmentHelper.getItemEnchantmentLevel(CraftEnchantment.getRaw(ench), handle);
+ // Paper start - replace to allow custom enchantments
+ final ListTag enchantments = this.handle.getEnchantmentTags();
+ for (int i = 0; i < enchantments.size(); i++) {
+ final CompoundTag tag = enchantments.getCompound(i);
+ final String id = tag.getString(CraftMetaItem.ENCHANTMENTS_ID.NBT);
+ final Enchantment enchant = Enchantment.getByKey(CraftNamespacedKey.fromStringOrNull(id));
+ if (ench.equals(enchant)) {
+ return EnchantmentHelper.getEnchantmentLevel(tag);
+ }
+ }
+ return 0;
+ // Paper end - replace to allow custom enchantments
}
@Override
public int removeEnchantment(Enchantment ench) {
Preconditions.checkArgument(ench != null, "Enchantment cannot be null");
- ListTag list = CraftItemStack.getEnchantmentList(this.handle), listCopy;
- if (list == null) {
- return 0;
- }
- int index = Integer.MIN_VALUE;
- int level = Integer.MIN_VALUE;
- int size = list.size();
-
- for (int i = 0; i < size; i++) {
- CompoundTag enchantment = (CompoundTag) list.get(i);
- String id = enchantment.getString(ENCHANTMENTS_ID.NBT);
- if (ench.getKey().equals(NamespacedKey.fromString(id))) {
- index = i;
- level = 0xffff & enchantment.getShort(ENCHANTMENTS_LVL.NBT);
- break;
- }
- }
-
- if (index == Integer.MIN_VALUE) {
- return 0;
- }
- if (size == 1) {
- this.handle.getTag().remove(ENCHANTMENTS.NBT);
- if (this.handle.getTag().isEmpty()) {
- this.handle.setTag(null);
- }
- return level;
- }
-
- // This is workaround for not having an index removal
- listCopy = new ListTag();
- for (int i = 0; i < size; i++) {
- if (i != index) {
- listCopy.add(list.get(i));
- }
+ // Paper start - replace entire method
+ int level = getEnchantmentLevel(ench);
+ if (level > 0) {
+ final ItemMeta itemMeta = this.getItemMeta();
+ if (itemMeta == null) return 0;
+ itemMeta.removeEnchant(ench);
+ this.setItemMeta(itemMeta);
}
- this.handle.getTag().put(ENCHANTMENTS.NBT, listCopy);
+ // Paper end
return level;
}
@Override
public Map<Enchantment, Integer> getEnchantments() {
- return CraftItemStack.getEnchantments(this.handle);
+ return this.hasItemMeta() ? this.getItemMeta().getEnchants() : ImmutableMap.<Enchantment, Integer>of(); // Paper - use Item Meta
}
static Map<Enchantment, Integer> getEnchantments(net.minecraft.world.item.ItemStack item) {
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index 44244166ec4e8ac070404101219efbc0e5f1d168..092695d4b45205fe2290f8f4375e881aaf89817d 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -6,6 +6,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.ImmutableSortedMap; // Paper
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
@@ -23,6 +24,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
+import java.util.Comparator; // Paper
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
@@ -33,6 +35,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
+import java.util.TreeMap; // Paper
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
@@ -275,7 +278,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
private List<String> lore; // null and empty are two different states internally
private Integer customModelData;
private CompoundTag blockData;
- private Map<Enchantment, Integer> enchantments;
+ private EnchantmentMap enchantments; // Paper
private Multimap<Attribute, AttributeModifier> attributeModifiers;
private int repairCost;
private int hideFlag;
@@ -286,7 +289,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
private CompoundTag internalTag;
- final Map<String, Tag> unhandledTags = new HashMap<String, Tag>(); // Visible for testing only
+ final Map<String, Tag> unhandledTags = new TreeMap<String, Tag>(); // Visible for testing only // Paper
private CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftMetaItem.DATA_TYPE_REGISTRY);
private int version = CraftMagicNumbers.INSTANCE.getDataVersion(); // Internal use only
@@ -307,7 +310,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
this.blockData = meta.blockData;
if (meta.enchantments != null) { // Spigot
- this.enchantments = new LinkedHashMap<Enchantment, Integer>(meta.enchantments);
+ this.enchantments = new EnchantmentMap(meta.enchantments); // Paper
}
if (meta.hasAttributeModifiers()) {
@@ -390,13 +393,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
}
- static Map<Enchantment, Integer> buildEnchantments(CompoundTag tag, ItemMetaKey key) {
+ static EnchantmentMap buildEnchantments(CompoundTag tag, ItemMetaKey key) { // Paper
if (!tag.contains(key.NBT)) {
return null;
}
ListTag ench = tag.getList(key.NBT, CraftMagicNumbers.NBT.TAG_COMPOUND);
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(ench.size());
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
for (int i = 0; i < ench.size(); i++) {
String id = ((CompoundTag) ench.get(i)).getString(ENCHANTMENTS_ID.NBT);
@@ -549,13 +552,13 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
}
- static Map<Enchantment, Integer> buildEnchantments(Map<String, Object> map, ItemMetaKey key) {
+ static EnchantmentMap buildEnchantments(Map<String, Object> map, ItemMetaKey key) { // Paper
Map<?, ?> ench = SerializableMeta.getObject(Map.class, map, key.BUKKIT, true);
if (ench == null) {
return null;
}
- Map<Enchantment, Integer> enchantments = new LinkedHashMap<Enchantment, Integer>(ench.size());
+ EnchantmentMap enchantments = new EnchantmentMap(); // Paper
for (Map.Entry<?, ?> entry : ench.entrySet()) {
// Doctor older enchants
String enchantKey = entry.getKey().toString();
@@ -831,14 +834,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
@Override
public Map<Enchantment, Integer> getEnchants() {
- return this.hasEnchants() ? ImmutableMap.copyOf(enchantments) : ImmutableMap.<Enchantment, Integer>of();
+ return this.hasEnchants() ? ImmutableSortedMap.copyOfSorted(this.enchantments) : ImmutableMap.<Enchantment, Integer>of(); // Paper
}
@Override
public boolean addEnchant(Enchantment ench, int level, boolean ignoreRestrictions) {
Preconditions.checkArgument(ench != null, "Enchantment cannot be null");
if (this.enchantments == null) {
- this.enchantments = new LinkedHashMap<Enchantment, Integer>(4);
+ this.enchantments = new EnchantmentMap(); // Paper
}
if (ignoreRestrictions || level >= ench.getStartLevel() && level <= ench.getMaxLevel()) {
@@ -1227,7 +1230,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
clone.customModelData = this.customModelData;
clone.blockData = this.blockData;
if (this.enchantments != null) {
- clone.enchantments = new LinkedHashMap<Enchantment, Integer>(this.enchantments);
+ clone.enchantments = new EnchantmentMap(this.enchantments); // Paper
}
if (this.hasAttributeModifiers()) {
clone.attributeModifiers = LinkedHashMultimap.create(this.attributeModifiers);
@@ -1469,4 +1472,22 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
return CraftMetaItem.HANDLED_TAGS;
}
}
+
+ // Paper start
+ private static class EnchantmentMap extends TreeMap<Enchantment, Integer> {
+ private EnchantmentMap(Map<Enchantment, Integer> enchantments) {
+ this();
+ putAll(enchantments);
+ }
+
+ private EnchantmentMap() {
+ super(Comparator.comparing(o -> o.getKey().toString()));
+ }
+
+ public EnchantmentMap clone() {
+ return (EnchantmentMap) super.clone();
+ }
+ }
+ // Paper end
+
}

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Mar 2016 15:12:22 -0400
Subject: [PATCH] Configurable Non Player Arrow Despawn Rate
Can set a much shorter despawn rate for arrows that players can not pick up.
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 37356efff435444b29d6d6682f365a329ebdd92e..7acd5d9fb7f7d3e067de779a9e3f0cedb587c68a 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
@@ -312,7 +312,7 @@ public abstract class AbstractArrow extends Projectile {
protected void tickDespawn() {
++this.life;
- if (this.life >= ((this instanceof ThrownTrident) ? this.level().spigotConfig.tridentDespawnRate : this.level().spigotConfig.arrowDespawnRate)) { // Spigot
+ if (this.life >= (pickup == Pickup.CREATIVE_ONLY ? this.level().paperConfig().entities.spawning.creativeArrowDespawnRate.value() : (pickup == Pickup.DISALLOWED ? this.level().paperConfig().entities.spawning.nonPlayerArrowDespawnRate.value() : ((this instanceof ThrownTrident) ? this.level().spigotConfig.tridentDespawnRate : this.level().spigotConfig.arrowDespawnRate)))) { // Spigot // Paper - TODO: Extract this to init?
this.discard();
}

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Mar 2016 20:16:03 -0400
Subject: [PATCH] Add World Util Methods
Methods that can be used for other patches to help improve logic.
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index e253531f5da93d2a5b328e1af6eef2a6d9a72bc1..d48ad601dc9f8b3ed3bc0e2dd068981eb7613c30 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -221,7 +221,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
public final LevelStorageSource.LevelStorageAccess convertable;
public final UUID uuid;
- public LevelChunk getChunkIfLoaded(int x, int z) {
+ @Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI
return this.chunkSource.getChunk(x, z, false);
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 8149286827d9b609be47a4ded0413ca11f7858de..809f7db469583ea90fbb165cf180dc87055c6105 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -342,6 +342,22 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return chunk == null ? null : chunk.getFluidState(blockposition);
}
+ public final boolean isLoadedAndInBounds(BlockPos blockposition) { // Paper - final for inline
+ return getWorldBorder().isWithinBounds(blockposition) && getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) != null;
+ }
+
+ public @Nullable LevelChunk getChunkIfLoaded(int x, int z) { // Overridden in WorldServer for ABI compat which has final
+ return ((ServerLevel) this).getChunkSource().getChunkAtIfLoadedImmediately(x, z);
+ }
+ public final @Nullable LevelChunk getChunkIfLoaded(BlockPos blockposition) {
+ return ((ServerLevel) this).getChunkSource().getChunkAtIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4);
+ }
+
+ // reduces need to do isLoaded before getType
+ public final @Nullable BlockState getBlockStateIfLoadedAndInBounds(BlockPos blockposition) {
+ return getWorldBorder().isWithinBounds(blockposition) ? getBlockStateIfLoaded(blockposition) : null;
+ }
+
@Override
public final ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { // Paper - final for inline
// Paper end

View file

@ -1,48 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jedediah Smith <jedediah@silencegreys.com>
Date: Sun, 21 Jun 2015 15:07:20 -0400
Subject: [PATCH] Custom replacement for eaten items
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index ddf083a54015f943e3e00ae6d5f73f8e127f6dc2..d8ecc90465dfc54319d7f2478979e9aaee42f5a2 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3639,10 +3639,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
this.triggerItemUseEffects(this.useItem, 16);
// CraftBukkit start - fire PlayerItemConsumeEvent
ItemStack itemstack;
+ PlayerItemConsumeEvent event = null; // Paper
if (this instanceof ServerPlayer) {
org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(this.useItem);
org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(enumhand);
- PlayerItemConsumeEvent event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem, hand);
+ event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem, hand); // Paper
this.level().getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
@@ -3656,6 +3657,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
} else {
itemstack = this.useItem.finishUsingItem(this.level(), this);
}
+ // Paper start - save the default replacement item and change it if necessary
+ final ItemStack defaultReplacement = itemstack;
+ if (event != null && event.getReplacement() != null) {
+ itemstack = CraftItemStack.asNMSCopy(event.getReplacement());
+ }
+ // Paper end
// CraftBukkit end
if (itemstack != this.useItem) {
@@ -3663,6 +3670,11 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
this.stopUsingItem();
+ // Paper start - if the replacement is anything but the default, update the client inventory
+ if (this instanceof ServerPlayer && !com.google.common.base.Objects.equal(defaultReplacement, itemstack)) {
+ ((ServerPlayer) this).getBukkitEntity().updateInventory();
+ }
+ // Paper end
}
}

View file

@ -1,159 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sat, 31 Oct 2020 18:43:02 -0500
Subject: [PATCH] Strip raytracing for EntityLiving#hasLineOfSight
The BlockGetter#clip method is very wasteful in both allocations,
and in logic. While EntityLiving#hasLineOfSight provides static
parameters for collisions with blocks and fluids, the method still does
a lot of dynamic checks for both of these, which result in extra work.
As well, since the fluid collision option is set to NONE, the entire
fluid collision system is completely unneeded, yet used anyways.
Copyright (C) 2020 Technove LLC
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index d8ecc90465dfc54319d7f2478979e9aaee42f5a2..53e666df97e74bbb8e96207ebc50e3e9acc455de 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3407,7 +3407,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
Vec3 vec3d = new Vec3(this.getX(), this.getEyeY(), this.getZ());
Vec3 vec3d1 = new Vec3(entity.getX(), entity.getEyeY(), entity.getZ());
- return vec3d1.distanceTo(vec3d) > 128.0D ? false : this.level().clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() == HitResult.Type.MISS;
+ return vec3d1.distanceTo(vec3d) > 128.0D ? false : this.level().clipDirect(vec3d, vec3d1, net.minecraft.world.phys.shapes.CollisionContext.of(this)) == HitResult.Type.MISS; // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java
index d6d8bbc98fc71997cb52521d59ebb59d727d3c22..3b31a1927aaed7fffc1b4f4bcefc12120d66af3d 100644
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
@@ -68,6 +68,19 @@ public interface BlockGetter extends LevelHeightAccessor {
});
}
+ // Paper start - Broken down variant of the method below, used by Level#clipDirect
+ @Nullable
+ default BlockHitResult.Type clipDirect(Vec3 start, Vec3 end, BlockPos pos, BlockState state, net.minecraft.world.phys.shapes.CollisionContext collisionContext) {
+ if (state.isAir()) {
+ return null;
+ }
+
+ final VoxelShape voxelshape = ClipContext.Block.COLLIDER.get(state, this, pos, collisionContext);
+ final BlockHitResult hitResult = this.clipWithInteractionOverride(start, end, pos, voxelshape, state);
+ return hitResult == null ? null : hitResult.getType();
+ }
+ // Paper end
+
// CraftBukkit start - moved block handling into separate method for use by Block#rayTrace
default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) {
BlockState iblockdata = this.getBlockState(blockposition);
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 809f7db469583ea90fbb165cf180dc87055c6105..37d5abf5a18b90695d1cea9e365c764e93b918bf 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -283,6 +283,90 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
return null;
}
+ // Paper start - Broken down method of raytracing for EntityLiving#hasLineOfSight, replaces BlockGetter#clip(CollisionContext)
+ public net.minecraft.world.phys.BlockHitResult.Type clipDirect(Vec3 start, Vec3 end, net.minecraft.world.phys.shapes.CollisionContext collisionContext) {
+ // most of this code comes from BlockGetter#clip(CollisionContext, BiFunction, Function), but removes the needless functions
+ if (start.equals(end)) {
+ return net.minecraft.world.phys.BlockHitResult.Type.MISS;
+ }
+
+ final double endX = Mth.lerp(-1.0E-7D, end.x, start.x);
+ final double endY = Mth.lerp(-1.0E-7D, end.y, start.y);
+ final double endZ = Mth.lerp(-1.0E-7D, end.z, start.z);
+
+ final double startX = Mth.lerp(-1.0E-7D, start.x, end.x);
+ final double startY = Mth.lerp(-1.0E-7D, start.y, end.y);
+ final double startZ = Mth.lerp(-1.0E-7D, start.z, end.z);
+
+ int currentX = Mth.floor(startX);
+ int currentY = Mth.floor(startY);
+ int currentZ = Mth.floor(startZ);
+
+ final BlockPos.MutableBlockPos currentBlock = new BlockPos.MutableBlockPos(currentX, currentY, currentZ);
+
+ LevelChunk chunk = this.getChunkIfLoaded(currentBlock);
+ if (chunk == null) {
+ return net.minecraft.world.phys.BlockHitResult.Type.MISS;
+ }
+
+ final net.minecraft.world.phys.BlockHitResult.Type initialCheck = this.clipDirect(start, end, currentBlock, chunk.getBlockState(currentBlock), collisionContext);
+ if (initialCheck != null) {
+ return initialCheck;
+ }
+
+ final double diffX = endX - startX;
+ final double diffY = endY - startY;
+ final double diffZ = endZ - startZ;
+
+ final int xDirection = Mth.sign(diffX);
+ final int yDirection = Mth.sign(diffY);
+ final int zDirection = Mth.sign(diffZ);
+
+ final double normalizedX = xDirection == 0 ? Double.MAX_VALUE : (double) xDirection / diffX;
+ final double normalizedY = yDirection == 0 ? Double.MAX_VALUE : (double) yDirection / diffY;
+ final double normalizedZ = zDirection == 0 ? Double.MAX_VALUE : (double) zDirection / diffZ;
+
+ double normalizedXDirection = normalizedX * (xDirection > 0 ? 1.0D - Mth.frac(startX) : Mth.frac(startX));
+ double normalizedYDirection = normalizedY * (yDirection > 0 ? 1.0D - Mth.frac(startY) : Mth.frac(startY));
+ double normalizedZDirection = normalizedZ * (zDirection > 0 ? 1.0D - Mth.frac(startZ) : Mth.frac(startZ));
+
+ net.minecraft.world.phys.BlockHitResult.Type result;
+
+ do {
+ if (normalizedXDirection > 1.0D && normalizedYDirection > 1.0D && normalizedZDirection > 1.0D) {
+ return net.minecraft.world.phys.BlockHitResult.Type.MISS;
+ }
+
+ if (normalizedXDirection < normalizedYDirection) {
+ if (normalizedXDirection < normalizedZDirection) {
+ currentX += xDirection;
+ normalizedXDirection += normalizedX;
+ } else {
+ currentZ += zDirection;
+ normalizedZDirection += normalizedZ;
+ }
+ } else if (normalizedYDirection < normalizedZDirection) {
+ currentY += yDirection;
+ normalizedYDirection += normalizedY;
+ } else {
+ currentZ += zDirection;
+ normalizedZDirection += normalizedZ;
+ }
+
+ currentBlock.set(currentX, currentY, currentZ);
+ if (chunk.getPos().x != currentBlock.getX() >> 4 || chunk.getPos().z != currentBlock.getZ() >> 4) {
+ chunk = this.getChunkIfLoaded(currentBlock);
+ if (chunk == null) {
+ return net.minecraft.world.phys.BlockHitResult.Type.MISS;
+ }
+ }
+ result = this.clipDirect(start, end, currentBlock, chunk.getBlockState(currentBlock), collisionContext);
+ } while (result == null);
+
+ return result;
+ }
+ // Paper end
+
public boolean isInWorldBounds(BlockPos pos) {
return !this.isOutsideBuildHeight(pos) && Level.isInWorldBoundsHorizontal(pos);
}

View file

@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 27 Sep 2015 01:18:02 -0400
Subject: [PATCH] handle NaN health/absorb values and repair bad data
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 53e666df97e74bbb8e96207ebc50e3e9acc455de..8435d0c62c716d4cce5d8b512d8a42658f774876 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -794,7 +794,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
@Override
public void readAdditionalSaveData(CompoundTag nbt) {
- this.setAbsorptionAmount(nbt.getFloat("AbsorptionAmount"));
+ // Paper start - jvm keeps optimizing the setter
+ float absorptionAmount = nbt.getFloat("AbsorptionAmount");
+ if (Float.isNaN(absorptionAmount)) {
+ absorptionAmount = 0;
+ }
+ this.setAbsorptionAmount(absorptionAmount);
+ // Paper end
if (nbt.contains("Attributes", 9) && this.level() != null && !this.level().isClientSide) {
this.getAttributes().load(nbt.getList("Attributes", 10));
}
@@ -1312,6 +1318,10 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
public void setHealth(float health) {
+ // Paper start
+ if (Float.isNaN(health)) { health = getMaxHealth(); if (this.valid) {
+ System.err.println("[NAN-HEALTH] " + getScoreboardName() + " had NaN health set");
+ } } // Paper end
// CraftBukkit start - Handle scaled health
if (this instanceof ServerPlayer) {
org.bukkit.craftbukkit.entity.CraftPlayer player = ((ServerPlayer) this).getBukkitEntity();
@@ -3472,7 +3482,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
public void setAbsorptionAmount(float amount) {
- if (amount < 0.0F) {
+ if (amount < 0.0F || Float.isNaN(amount)) { // Paper
amount = 0.0F;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 038c34e62903afd19fb25b2125d5ed243e081139..4e85199be8a1a7472d13856a697ec500b9566341 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2149,6 +2149,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
public void setRealHealth(double health) {
+ if (Double.isNaN(health)) {return;} // Paper
this.health = health;
}

View file

@ -1,113 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 22 Mar 2016 00:33:47 -0400
Subject: [PATCH] Use a Shared Random for Entities
Reduces memory usage and provides ensures more randomness, Especially since a lot of garbage entity objects get created.
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 2d37f4da83282e3430353e01c756a0d952150360..2f15c9df59ebfbe7619e190b8d6ef1fe122809f8 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -162,6 +162,79 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
return tag.contains("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
}
+ // Paper start
+ public static RandomSource SHARED_RANDOM = new RandomRandomSource();
+ private static final class RandomRandomSource extends java.util.Random implements net.minecraft.world.level.levelgen.BitRandomSource {
+ private boolean locked = false;
+
+ @Override
+ public synchronized void setSeed(long seed) {
+ if (locked) {
+ LOGGER.error("Ignoring setSeed on Entity.SHARED_RANDOM", new Throwable());
+ } else {
+ super.setSeed(seed);
+ locked = true;
+ }
+ }
+
+ @Override
+ public RandomSource fork() {
+ return new net.minecraft.world.level.levelgen.LegacyRandomSource(this.nextLong());
+ }
+
+ @Override
+ public net.minecraft.world.level.levelgen.PositionalRandomFactory forkPositional() {
+ return new net.minecraft.world.level.levelgen.LegacyRandomSource.LegacyPositionalRandomFactory(this.nextLong());
+ }
+
+ // these below are added to fix reobf issues that I don't wanna deal with right now
+ @Override
+ public int next(int bits) {
+ return super.next(bits);
+ }
+
+ @Override
+ public int nextInt(int origin, int bound) {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(origin, bound);
+ }
+
+ @Override
+ public long nextLong() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextLong();
+ }
+
+ @Override
+ public int nextInt() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt();
+ }
+
+ @Override
+ public int nextInt(int bound) {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextInt(bound);
+ }
+
+ @Override
+ public boolean nextBoolean() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextBoolean();
+ }
+
+ @Override
+ public float nextFloat() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextFloat();
+ }
+
+ @Override
+ public double nextDouble() {
+ return net.minecraft.world.level.levelgen.BitRandomSource.super.nextDouble();
+ }
+
+ @Override
+ public double nextGaussian() {
+ return super.nextGaussian();
+ }
+ }
+ // Paper end
+
private CraftEntity bukkitEntity;
public CraftEntity getBukkitEntity() {
@@ -406,7 +479,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
this.bb = Entity.INITIAL_AABB;
this.stuckSpeedMultiplier = Vec3.ZERO;
this.nextStep = 1.0F;
- this.random = RandomSource.create();
+ this.random = SHARED_RANDOM; // Paper
this.remainingFireTicks = -this.getFireImmuneTicks();
this.fluidHeight = new Object2DoubleArrayMap(2);
this.fluidOnEyes = new HashSet();
diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java
index 891d8b4c8cb73d5e310970066831ab3e2af14e91..f60c4cd0543fd5d50fa7e2c1a9e8381227adb540 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Squid.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java
@@ -44,7 +44,7 @@ public class Squid extends WaterAnimal {
public Squid(EntityType<? extends Squid> type, Level world) {
super(type, world);
- this.random.setSeed((long)this.getId());
+ //this.random.setSeed((long)this.getId()); // Paper - we set the random to shared, do not clobber the seed
this.tentacleSpeed = 1.0F / (this.random.nextFloat() + 1.0F) * 0.2F;
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 22 Mar 2016 12:04:28 -0500
Subject: [PATCH] Configurable spawn chances for skeleton horses
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index d48ad601dc9f8b3ed3bc0e2dd068981eb7613c30..5cde98b0225799bccdb84ce6b6cf06b904d5986c 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -837,7 +837,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
blockposition = this.findLightningTargetAround(this.getBlockRandomPos(j, 0, k, 15));
if (this.isRainingAt(blockposition)) {
DifficultyInstance difficultydamagescaler = this.getCurrentDifficultyAt(blockposition);
- boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * 0.01D && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD);
+ boolean flag1 = this.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && this.random.nextDouble() < (double) difficultydamagescaler.getEffectiveDifficulty() * this.paperConfig().entities.spawning.skeletonHorseThunderSpawnChance.or(0.01D) && !this.getBlockState(blockposition.below()).is(Blocks.LIGHTNING_ROD); // Paper
if (flag1) {
SkeletonHorse entityhorseskeleton = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this);

View file

@ -1,166 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 3 Mar 2016 02:07:55 -0600
Subject: [PATCH] Optimize isInWorldBounds and getBlockState for inlining
Hot methods, so reduce # of instructions for the method.
Move is valid location test to the BlockPosition class so that it can access local variables.
Replace all calls to the new place to the unnecessary forward.
Optimize getType and getBlockData to manually inline and optimize the calls
diff --git a/src/main/java/net/minecraft/core/Vec3i.java b/src/main/java/net/minecraft/core/Vec3i.java
index 1b29c6872ebe54351f28c1f1f38b22561ba785ee..40950db0c242c65dfd4de247c86249354d12108f 100644
--- a/src/main/java/net/minecraft/core/Vec3i.java
+++ b/src/main/java/net/minecraft/core/Vec3i.java
@@ -31,6 +31,12 @@ public class Vec3i implements Comparable<Vec3i> {
});
}
+ // Paper start
+ public final boolean isInsideBuildHeightAndWorldBoundsHorizontal(net.minecraft.world.level.LevelHeightAccessor levelHeightAccessor) {
+ return getX() >= -30000000 && getZ() >= -30000000 && getX() < 30000000 && getZ() < 30000000 && !levelHeightAccessor.isOutsideBuildHeight(getY());
+ }
+ // Paper end
+
public Vec3i(int x, int y, int z) {
this.x = x;
this.y = y;
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 37d5abf5a18b90695d1cea9e365c764e93b918bf..5502d037279ba876f5e4c6728cc678f128bce9d4 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -368,7 +368,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Paper end
public boolean isInWorldBounds(BlockPos pos) {
- return !this.isOutsideBuildHeight(pos) && Level.isInWorldBoundsHorizontal(pos);
+ return pos.isInsideBuildHeightAndWorldBoundsHorizontal(this); // Paper - use better/optimized check
}
public static boolean isInSpawnableBounds(BlockPos pos) {
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
index 2caac1a3d80e6c490aa16aa6bc1067065b665c69..525c89bc926f13af6f94fc46c897525e37477eca 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -166,6 +166,7 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom
return GameEventListenerRegistry.NOOP;
}
+ public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper
@Nullable
public abstract BlockState setBlockState(BlockPos pos, BlockState state, boolean moved);
diff --git a/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
index f49cc61840c6588fca301b4c5c3aaeede03a323e..785fa679860413b736122f8e88a92e683cbdd99f 100644
--- a/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/EmptyLevelChunk.java
@@ -55,6 +55,12 @@ public class EmptyLevelChunk extends LevelChunk {
public void setBlockEmptinessMap(final boolean[] emptinessMap) {}
// Paper end - starlight
+ // Paper start
+ @Override
+ public BlockState getBlockState(int x, int y, int z) {
+ return Blocks.VOID_AIR.defaultBlockState();
+ }
+ // Paper end
@Override
public BlockState getBlockState(BlockPos pos) {
return Blocks.VOID_AIR.defaultBlockState();
diff --git a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
index 60e760b42dd6471a229dfd45490dcf8c51979d35..4a3ac7dedf5cb1e76f16ec4f18e82afc717d0ced 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java
@@ -91,6 +91,12 @@ public class ImposterProtoChunk extends ProtoChunk {
public BlockState getBlockState(BlockPos pos) {
return this.wrapped.getBlockState(pos);
}
+ // Paper start
+ @Override
+ public final BlockState getBlockState(final int x, final int y, final int z) {
+ return this.wrapped.getBlockStateFinal(x, y, z);
+ }
+ // Paper end
@Override
public FluidState getFluidState(BlockPos pos) {
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 36701f196756dc7c6820cac516ff880d00a43b17..72637bb342f1260debf925f5b3fde8ec7dd3cfff 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -295,12 +295,29 @@ public class LevelChunk extends ChunkAccess {
}
}
+ // Paper start - Optimize getBlockData to reduce instructions
@Override
public BlockState getBlockState(BlockPos pos) {
- int i = pos.getX();
- int j = pos.getY();
- int k = pos.getZ();
+ return this.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ());
+ }
+
+ @Override
+ public BlockState getBlockState(final int x, final int y, final int z) {
+ return this.getBlockStateFinal(x, y, z);
+ }
+ public final BlockState getBlockStateFinal(final int x, final int y, final int z) {
+ // Method body / logic copied from below
+ final int i = this.getSectionIndex(y);
+ if (i < 0 || i >= this.sections.length || this.sections[i].nonEmptyBlockCount == 0 || this.sections[i].hasOnlyAir()) {
+ return Blocks.AIR.defaultBlockState();
+ }
+ // Inlined ChunkSection.getType() and DataPaletteBlock.a(int,int,int)
+ return this.sections[i].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15);
+ }
+
+ public BlockState getBlockState_unused(int i, int j, int k) {
+ // Paper end
if (this.level.isDebug()) {
BlockState iblockdata = null;
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
index d59392c322936ce89b759ac9787c8f4f0b228af6..2c3ea88bac229df67bd742e16d2106d80bcc8889 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -19,7 +19,7 @@ public class LevelChunkSection {
public static final int SECTION_HEIGHT = 16;
public static final int SECTION_SIZE = 4096;
public static final int BIOME_CONTAINER_BITS = 2;
- private short nonEmptyBlockCount;
+ short nonEmptyBlockCount; // Paper - package-private
private short tickingBlockCount;
private short tickingFluidCount;
public final PalettedContainer<BlockState> states;
diff --git a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
index b2c0c7fd06fcd720b4c0875f08a90b6b672c96b2..6c72eb36020bc05104b21e52cea89de09b85f2d7 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ProtoChunk.java
@@ -92,14 +92,18 @@ public class ProtoChunk extends ChunkAccess {
@Override
public BlockState getBlockState(BlockPos pos) {
- int i = pos.getY();
- if (this.isOutsideBuildHeight(i)) {
+ // Paper start
+ return getBlockState(pos.getX(), pos.getY(), pos.getZ());
+ }
+ public BlockState getBlockState(final int x, final int y, final int z) {
+ if (this.isOutsideBuildHeight(y)) {
return Blocks.VOID_AIR.defaultBlockState();
} else {
- LevelChunkSection levelChunkSection = this.getSection(this.getSectionIndex(i));
- return levelChunkSection.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : levelChunkSection.getBlockState(pos.getX() & 15, i & 15, pos.getZ() & 15);
+ LevelChunkSection levelChunkSection = this.getSections()[this.getSectionIndex(y)];
+ return levelChunkSection.hasOnlyAir() ? Blocks.AIR.defaultBlockState() : levelChunkSection.getBlockState(x & 15, y & 15, z & 15);
}
}
+ // Paper end
@Override
public FluidState getFluidState(BlockPos pos) {

View file

@ -1,70 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 19:55:45 -0400
Subject: [PATCH] Only process BlockPhysicsEvent if a plugin has a listener
Saves on some object allocation and processing when no plugin listens to this
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index ebfc20247ac5a548e6616a099b8885db9c7a8d25..4b9de3ca81b60eb4a916006cdfbc2a630a390a39 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1364,6 +1364,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
+ worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
this.profiler.push(() -> {
return worldserver + " " + worldserver.dimension().location();
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 5cde98b0225799bccdb84ce6b6cf06b904d5986c..699fc5f11efa8240723854cd2e91877b278f9495 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -220,6 +220,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
// CraftBukkit start
public final LevelStorageSource.LevelStorageAccess convertable;
public final UUID uuid;
+ public boolean hasPhysicsEvent = true; // Paper
@Override public LevelChunk getChunkIfLoaded(int x, int z) { // Paper - this was added in world too but keeping here for NMS ABI
return this.chunkSource.getChunk(x, z, false);
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 5502d037279ba876f5e4c6728cc678f128bce9d4..ba7760b0b478c6f24dcbaa64919a4766e107a720 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -580,7 +580,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// CraftBukkit start
iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam
CraftWorld world = ((ServerLevel) this).getWorld();
- if (world != null) {
+ if (world != null && ((ServerLevel)this).hasPhysicsEvent) { // Paper
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata));
this.getCraftServer().getPluginManager().callEvent(event);
diff --git a/src/main/java/net/minecraft/world/level/block/BushBlock.java b/src/main/java/net/minecraft/world/level/block/BushBlock.java
index d40e791529911ca81398ac267a819415da91502a..03fde6e47c4a347c62fe9b4a3351769aedf874f6 100644
--- a/src/main/java/net/minecraft/world/level/block/BushBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BushBlock.java
@@ -24,7 +24,7 @@ public class BushBlock extends Block {
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
// CraftBukkit start
if (!state.canSurvive(world, pos)) {
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) {
+ if (!(world instanceof net.minecraft.server.level.ServerLevel && ((net.minecraft.server.level.ServerLevel) world).hasPhysicsEvent) || !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper
return Blocks.AIR.defaultBlockState();
}
}
diff --git a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
index ec66f00703fcb68aa567b2d14a756729371320e0..9db66b393e057d93a8025b803ae0ad2a1bca61f6 100644
--- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java
@@ -95,7 +95,7 @@ public class DoublePlantBlock extends BushBlock {
protected static void preventCreativeDropFromBottomPart(Level world, BlockPos pos, BlockState state, Player player) {
// CraftBukkit start
- if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) {
+ if (((net.minecraft.server.level.ServerLevel)world).hasPhysicsEvent && org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper
return;
}
// CraftBukkit end

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 20:32:58 -0400
Subject: [PATCH] Entity AddTo/RemoveFrom World Events
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 699fc5f11efa8240723854cd2e91877b278f9495..7da059a2e8560250021654f3d5586027c15c7dd3 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2373,6 +2373,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
entity.setOrigin(entity.getOriginVector().toLocation(getWorld()));
}
// Paper end
+ new com.destroystokyo.paper.event.entity.EntityAddToWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
}
public void onTrackingEnd(Entity entity) {
@@ -2448,6 +2449,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
}
}
// CraftBukkit end
+ new com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent(entity.getBukkitEntity()).callEvent(); // Paper - fire while valid
}
public void onSectionChange(Entity entity) {

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 20:46:14 -0400
Subject: [PATCH] Configurable Chunk Inhabited Time
Vanilla stores how long a chunk has been active on a server, and dynamically scales some
aspects of vanilla gameplay to this factor.
For people who want all chunks to be treated equally, you can chose a fixed value.
This allows to fine-tune vanilla gameplay.
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 72637bb342f1260debf925f5b3fde8ec7dd3cfff..704f0500649acdbff2caf94f702a6685ecf4c986 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -280,6 +280,13 @@ public class LevelChunk extends ChunkAccess {
return new ChunkAccess.TicksToSave(this.blockTicks, this.fluidTicks);
}
+ // Paper start
+ @Override
+ public long getInhabitedTime() {
+ return this.level.paperConfig().chunks.fixedChunkInhabitedTime < 0 ? super.getInhabitedTime() : this.level.paperConfig().chunks.fixedChunkInhabitedTime;
+ }
+ // Paper end
+
@Override
public GameEventListenerRegistry getListenerRegistry(int ySectionCoord) {
Level world = this.level;

View file

@ -1,149 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 28 Mar 2016 21:22:26 -0400
Subject: [PATCH] EntityPathfindEvent
Fires when an Entity decides to start moving to a location.
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
index a8f69e48937b3ebd2f57a4da747e6762c4a77934..acd0b946cab86eb173e713535194d3a9347c7d48 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
@@ -40,7 +40,7 @@ public class FlyingPathNavigation extends PathNavigation {
@Override
public Path createPath(Entity entity, int distance) {
- return this.createPath(entity.blockPosition(), distance);
+ return this.createPath(entity.blockPosition(), entity, distance); // Paper - Forward target entity
}
@Override
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
index 518f47f52105e299e037fe2e7d5870d7555be4bc..71934af2dc4d209a9fbccfd36b5f2815ec196892 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
@@ -39,14 +39,14 @@ public class GroundPathNavigation extends PathNavigation {
}
@Override
- public Path createPath(BlockPos target, int distance) {
+ public Path createPath(BlockPos target, @javax.annotation.Nullable Entity entity, int distance) { // Paper
if (this.level.getBlockState(target).isAir()) {
BlockPos blockPos;
for(blockPos = target.below(); blockPos.getY() > this.level.getMinBuildHeight() && this.level.getBlockState(blockPos).isAir(); blockPos = blockPos.below()) {
}
if (blockPos.getY() > this.level.getMinBuildHeight()) {
- return super.createPath(blockPos.above(), distance);
+ return super.createPath(blockPos.above(), entity, distance); // Paper
}
while(blockPos.getY() < this.level.getMaxBuildHeight() && this.level.getBlockState(blockPos).isAir()) {
@@ -57,19 +57,19 @@ public class GroundPathNavigation extends PathNavigation {
}
if (!this.level.getBlockState(target).isSolid()) {
- return super.createPath(target, distance);
+ return super.createPath(target, entity, distance); // Paper
} else {
BlockPos blockPos2;
for(blockPos2 = target.above(); blockPos2.getY() < this.level.getMaxBuildHeight() && this.level.getBlockState(blockPos2).isSolid(); blockPos2 = blockPos2.above()) {
}
- return super.createPath(blockPos2, distance);
+ return super.createPath(blockPos2, entity, distance); // Paper
}
}
@Override
public Path createPath(Entity entity, int distance) {
- return this.createPath(entity.blockPosition(), distance);
+ return this.createPath(entity.blockPosition(), entity, distance); // Paper - Forward target entity
}
private int getSurfaceY() {
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
index f16e9bcefedb582a4bfe7a0b7ec8a97799f5e5ad..1a69a46340eee4f0273c373cc1a40b4d069a89d4 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java
@@ -110,7 +110,13 @@ public abstract class PathNavigation {
@Nullable
public Path createPath(BlockPos target, int distance) {
- return this.createPath(ImmutableSet.of(target), 8, false, distance);
+ // Paper start - add target entity parameter
+ return this.createPath(target, null, distance);
+ }
+ @Nullable
+ public Path createPath(BlockPos target, @Nullable Entity entity, int distance) {
+ return this.createPath(ImmutableSet.of(target), entity, 8, false, distance);
+ // Paper end
}
@Nullable
@@ -120,7 +126,7 @@ public abstract class PathNavigation {
@Nullable
public Path createPath(Entity entity, int distance) {
- return this.createPath(ImmutableSet.of(entity.blockPosition()), 16, true, distance);
+ return this.createPath(ImmutableSet.of(entity.blockPosition()), entity, 16, true, distance); // Paper
}
@Nullable
@@ -130,6 +136,16 @@ public abstract class PathNavigation {
@Nullable
protected Path createPath(Set<BlockPos> positions, int range, boolean useHeadPos, int distance, float followRange) {
+ return this.createPath(positions, null, range, useHeadPos, distance, followRange);
+ }
+
+ @Nullable
+ protected Path createPath(Set<BlockPos> positions, @Nullable Entity target, int range, boolean useHeadPos, int distance) {
+ return this.createPath(positions, target, range, useHeadPos, distance, (float) this.mob.getAttributeValue(Attributes.FOLLOW_RANGE));
+ }
+
+ @Nullable protected Path createPath(Set<BlockPos> positions, @Nullable Entity target, int range, boolean useHeadPos, int distance, float followRange) {
+ // Paper end
if (positions.isEmpty()) {
return null;
} else if (this.mob.getY() < (double)this.level.getMinBuildHeight()) {
@@ -139,6 +155,23 @@ public abstract class PathNavigation {
} else if (this.path != null && !this.path.isDone() && positions.contains(this.targetPos)) {
return this.path;
} else {
+ // Paper start - Pathfind event
+ boolean copiedSet = false;
+ for (BlockPos possibleTarget : positions) {
+ if (!new com.destroystokyo.paper.event.entity.EntityPathfindEvent(this.mob.getBukkitEntity(),
+ io.papermc.paper.util.MCUtil.toLocation(this.mob.level(), possibleTarget), target == null ? null : target.getBukkitEntity()).callEvent()) {
+ if (!copiedSet) {
+ copiedSet = true;
+ positions = new java.util.HashSet<>(positions);
+ }
+ // note: since we copy the set this remove call is safe, since we're iterating over the old copy
+ positions.remove(possibleTarget);
+ if (positions.isEmpty()) {
+ return null;
+ }
+ }
+ }
+ // Paper end
this.level.getProfiler().push("pathfind");
BlockPos blockPos = useHeadPos ? this.mob.blockPosition().above() : this.mob.blockPosition();
int i = (int)(followRange + (float)range);
diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
index e9b49c72aa73dfcef6c136d9ed7bb5044fe8405d..2d1b2b84d7cf5bafe2cccfa0dec2bae805dbe7cf 100644
--- a/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/WallClimberNavigation.java
@@ -16,9 +16,9 @@ public class WallClimberNavigation extends GroundPathNavigation {
}
@Override
- public Path createPath(BlockPos target, int distance) {
+ public Path createPath(BlockPos target, @Nullable Entity entity, int distance) { // Paper
this.pathToPosition = target;
- return super.createPath(target, distance);
+ return super.createPath(target, entity, distance); // Paper
}
@Override

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antony Riley <antony@cyberiantiger.org>
Date: Tue, 29 Mar 2016 08:22:55 +0300
Subject: [PATCH] Sanitise RegionFileCache and make configurable.
RegionFileCache prior to this patch would close every single open region
file upon reaching a size of 256.
This patch modifies that behaviour so it closes the the least recently
used RegionFile.
The implementation uses a LinkedHashMap as an LRU cache (modified from HashMap).
The maximum size of the RegionFileCache is also made configurable.
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index a16047cab2709d197489215de66bf24901523a1c..4c1b1ac36ef09a9cc8da6e8ee71f82d4a67478df 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -91,7 +91,7 @@ public class RegionFileStorage implements AutoCloseable {
return null;
}
// Paper end - cache regionfile does not exist state
- if (this.regionCache.size() >= 256) {
+ if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - configurable
((RegionFile) this.regionCache.removeLast()).close();
}

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 31 Mar 2016 19:17:58 -0400
Subject: [PATCH] Do not load chunks for Pathfinding
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
index b7995e6159c865f8e2e7865f7eb51936a9720311..10503d6d8b6daf645cf4360ee289d5e25144c976 100644
--- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
@@ -459,7 +459,12 @@ public class WalkNodeEvaluator extends NodeEvaluator {
for(int n = -1; n <= 1; ++n) {
if (l != 0 || n != 0) {
pos.set(i + l, j + m, k + n);
- BlockState blockState = world.getBlockState(pos);
+ // Paper start
+ BlockState blockState = world.getBlockStateIfLoaded(pos);
+ if (blockState == null) {
+ return BlockPathTypes.BLOCKED;
+ } else {
+ // Paper end
if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH)) {
return BlockPathTypes.DANGER_OTHER;
}
@@ -475,6 +480,7 @@ public class WalkNodeEvaluator extends NodeEvaluator {
if (blockState.is(Blocks.WITHER_ROSE) || blockState.is(Blocks.POINTED_DRIPSTONE)) {
return BlockPathTypes.DAMAGE_CAUTIOUS;
}
+ } // Paper
}
}
}
@@ -484,7 +490,8 @@ public class WalkNodeEvaluator extends NodeEvaluator {
}
protected static BlockPathTypes getBlockPathTypeRaw(BlockGetter world, BlockPos pos) {
- BlockState blockState = world.getBlockState(pos);
+ BlockState blockState = world.getBlockStateIfLoaded(pos); // Paper
+ if (blockState == null) return BlockPathTypes.BLOCKED; // Paper
Block block = blockState.getBlock();
if (blockState.isAir()) {
return BlockPathTypes.OPEN;

View file

@ -1,72 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jedediah Smith <jedediah@silencegreys.com>
Date: Sat, 2 Apr 2016 05:09:16 -0400
Subject: [PATCH] Add PlayerUseUnknownEntityEvent
Adds the PlayerUseUnknownEntityEvent to be used by plugins dealing with
virtual entities/entities that are not actually known to the server.
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
diff --git a/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java b/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
index 644a0fdea6576647539b96528717dbaeab498d93..221e64a66ff12a8de5c75992fc26a54a03b317e7 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ServerboundInteractPacket.java
@@ -169,4 +169,14 @@ public class ServerboundInteractPacket implements Packet<ServerGamePacketListene
buf.writeEnum(this.hand);
}
}
+
+ // Paper start - PlayerUseUnknownEntityEvent
+ public int getEntityId() {
+ return this.entityId;
+ }
+
+ public boolean isAttack() {
+ return this.action.getType() == ActionType.ATTACK;
+ }
+ // Paper end - PlayerUseUnknownEntityEvent
}
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 1c84143d271e70f6ffea301f3e93cd8ed8fd9bd1..6b87ed8b453b149bdd74eb3b164aa3bbcc8c2b13 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2522,8 +2522,38 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
});
}
}
+ // Paper start - PlayerUseUnknownEntityEvent
+ else {
+ packet.dispatch(new net.minecraft.network.protocol.game.ServerboundInteractPacket.Handler() {
+ @Override
+ public void onInteraction(net.minecraft.world.InteractionHand hand) {
+ ServerGamePacketListenerImpl.this.callPlayerUseUnknownEntityEvent(packet, hand, null);
+ }
+
+ @Override
+ public void onInteraction(net.minecraft.world.InteractionHand hand, net.minecraft.world.phys.Vec3 pos) {
+ ServerGamePacketListenerImpl.this.callPlayerUseUnknownEntityEvent(packet, hand, pos);
+ }
+
+ @Override
+ public void onAttack() {
+ ServerGamePacketListenerImpl.this.callPlayerUseUnknownEntityEvent(packet, net.minecraft.world.InteractionHand.MAIN_HAND, null);
+ }
+ });
+ }
+
+ }
+ private void callPlayerUseUnknownEntityEvent(ServerboundInteractPacket packet, InteractionHand hand, @Nullable net.minecraft.world.phys.Vec3 vector) {
+ this.cserver.getPluginManager().callEvent(new com.destroystokyo.paper.event.player.PlayerUseUnknownEntityEvent(
+ this.getCraftPlayer(),
+ packet.getEntityId(),
+ packet.isAttack(),
+ hand == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND,
+ vector != null ? new org.bukkit.util.Vector(vector.x, vector.y, vector.z) : null)
+ );
}
+ // Paper end - PlayerUseUnknownEntityEvent
@Override
public void handleClientCommand(ServerboundClientCommandPacket packet) {

View file

@ -1,26 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 3 Apr 2016 16:28:17 -0400
Subject: [PATCH] Configurable Grass Spread Tick Rate
diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
index 1df22561b2d39066b6b30f10ea43edd734e3b50a..1fe07f8f9b28faf076209f7ad235fd5dc948b294 100644
--- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java
@@ -2,6 +2,7 @@ package net.minecraft.world.level.block;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
+import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.RandomSource;
@@ -39,6 +40,7 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock {
@Override
public void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper
if (!SpreadingSnowyDirtBlock.canBeGrass(state, world, pos)) {
// CraftBukkit start
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, Blocks.DIRT.defaultBlockState()).isCancelled()) {

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 3 Apr 2016 17:48:50 -0400
Subject: [PATCH] Fix Cancelling BlockPlaceEvent triggering physics
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 7da059a2e8560250021654f3d5586027c15c7dd3..35b59c83a35bc3a4d05bc95b0caec1f1865589c0 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1598,6 +1598,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
@Override
public void updateNeighborsAt(BlockPos pos, Block sourceBlock) {
+ if (captureBlockStates) { return; } // Paper - Cancel all physics during placement
this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null);
}

View file

@ -1,118 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 5 Apr 2016 21:38:58 -0400
Subject: [PATCH] Optimize DataBits
Remove Debug checks as these are super hot and causing noticeable hits
Before: http://i.imgur.com/nQsMzAE.png
After: http://i.imgur.com/nJ46crB.png
Optimize redundant converting of static fields into an unsigned long each call by precomputing it in ctor
diff --git a/src/main/java/net/minecraft/util/SimpleBitStorage.java b/src/main/java/net/minecraft/util/SimpleBitStorage.java
index f677cc252d5510a2365e73dc42bd266e56115e83..2b3fd62dca2d1475075b5dcde56cea85b749cb44 100644
--- a/src/main/java/net/minecraft/util/SimpleBitStorage.java
+++ b/src/main/java/net/minecraft/util/SimpleBitStorage.java
@@ -11,8 +11,8 @@ public class SimpleBitStorage implements BitStorage {
private final long mask;
private final int size;
private final int valuesPerLong;
- private final int divideMul;
- private final int divideAdd;
+ private final int divideMul; private final long divideMulUnsigned; // Paper - referenced in b(int) with 2 Integer.toUnsignedLong calls
+ private final int divideAdd; private final long divideAddUnsigned; // Paper
private final int divideShift;
public SimpleBitStorage(int elementBits, int size, int[] data) {
@@ -56,8 +56,8 @@ public class SimpleBitStorage implements BitStorage {
this.mask = (1L << elementBits) - 1L;
this.valuesPerLong = (char)(64 / elementBits);
int i = 3 * (this.valuesPerLong - 1);
- this.divideMul = MAGIC[i + 0];
- this.divideAdd = MAGIC[i + 1];
+ this.divideMul = MAGIC[i + 0]; this.divideMulUnsigned = Integer.toUnsignedLong(this.divideMul); // Paper
+ this.divideAdd = MAGIC[i + 1]; this.divideAddUnsigned = Integer.toUnsignedLong(this.divideAdd); // Paper
this.divideShift = MAGIC[i + 2];
int j = (size + this.valuesPerLong - 1) / this.valuesPerLong;
if (data != null) {
@@ -73,15 +73,15 @@ public class SimpleBitStorage implements BitStorage {
}
private int cellIndex(int index) {
- long l = Integer.toUnsignedLong(this.divideMul);
- long m = Integer.toUnsignedLong(this.divideAdd);
- return (int)((long)index * l + m >> 32 >> this.divideShift);
+ //long l = Integer.toUnsignedLong(this.divideMul); // Paper
+ //long m = Integer.toUnsignedLong(this.divideAdd); // Paper
+ return (int) ((long) index * this.divideMulUnsigned + this.divideAddUnsigned >> 32 >> this.divideShift); // Paper
}
@Override
- public int getAndSet(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, this.mask, (long)value);
+ public final int getAndSet(int index, int value) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
+ //Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper
int i = this.cellIndex(index);
long l = this.data[i];
int j = (index - i * this.valuesPerLong) * this.bits;
@@ -91,9 +91,9 @@ public class SimpleBitStorage implements BitStorage {
}
@Override
- public void set(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, this.mask, (long)value);
+ public final void set(int index, int value) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
+ //Validate.inclusiveBetween(0L, this.mask, (long)value); // Paper
int i = this.cellIndex(index);
long l = this.data[i];
int j = (index - i * this.valuesPerLong) * this.bits;
@@ -101,8 +101,8 @@ public class SimpleBitStorage implements BitStorage {
}
@Override
- public int get(int index) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
+ public final int get(int index) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
int i = this.cellIndex(index);
long l = this.data[i];
int j = (index - i * this.valuesPerLong) * this.bits;
diff --git a/src/main/java/net/minecraft/util/ZeroBitStorage.java b/src/main/java/net/minecraft/util/ZeroBitStorage.java
index 0710c72441c832a93275f3f9bd9dd7643dc0f229..f0f764f36fb92c64ab2dc8a0a50c3f48321c3c9a 100644
--- a/src/main/java/net/minecraft/util/ZeroBitStorage.java
+++ b/src/main/java/net/minecraft/util/ZeroBitStorage.java
@@ -13,21 +13,21 @@ public class ZeroBitStorage implements BitStorage {
}
@Override
- public int getAndSet(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, 0L, (long)value);
+ public final int getAndSet(int index, int value) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper
return 0;
}
@Override
- public void set(int index, int value) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
- Validate.inclusiveBetween(0L, 0L, (long)value);
+ public final void set(int index, int value) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
+ //Validate.inclusiveBetween(0L, 0L, (long)value); // Paper
}
@Override
- public int get(int index) {
- Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index);
+ public final int get(int index) { // Paper - make final for inline
+ //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper
return 0;
}

View file

@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Wed, 6 Apr 2016 01:04:23 -0500
Subject: [PATCH] Option to use vanilla per-world scoreboard coloring on names
This change is basically a bandaid to fix CB's complete and utter lack
of support for vanilla scoreboard name modifications.
In the future, finding a way to merge the vanilla expectations in with
bukkit's concept of a display name would be preferable. There was a PR
for this on CB at one point but I can't find it. We may need to do this
ourselves at some point in the future.
diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
index 57081e84d50f7eca7ea11540b550da8269378e9e..e4fd372a1d585887287253a02531cd192929377b 100644
--- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
+++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java
@@ -19,6 +19,7 @@ import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.audience.ForwardingAudience;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
+import net.minecraft.ChatFormatting;
import net.minecraft.Optionull;
import net.minecraft.Util;
import net.minecraft.core.registries.Registries;
@@ -31,6 +32,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.util.LazyPlayerSet;
import org.bukkit.craftbukkit.util.Waitable;
@@ -367,10 +369,16 @@ public final class ChatProcessor {
}
static String legacyDisplayName(final CraftPlayer player) {
+ if (((org.bukkit.craftbukkit.CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) {
+ return legacySection().serialize(player.teamDisplayName()) + ChatFormatting.RESET;
+ }
return player.getDisplayName();
}
static Component displayName(final CraftPlayer player) {
+ if (((CraftWorld) player.getWorld()).getHandle().paperConfig().scoreboards.useVanillaWorldScoreboardNameColoring) {
+ return player.teamDisplayName();
+ }
return player.displayName();
}

View file

@ -1,109 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 13 Apr 2016 02:10:49 -0400
Subject: [PATCH] Configurable Player Collision
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
index 1294b38262505b0d54089e428df9b363219de1f0..ee37ec0de1ca969144824427ae42b0c81434a1b4 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
@@ -193,7 +193,7 @@ public class ClientboundSetPlayerTeamPacket implements Packet<ClientGamePacketLi
buf.writeComponent(this.displayName);
buf.writeByte(this.options);
buf.writeUtf(this.nametagVisibility);
- buf.writeUtf(this.collisionRule);
+ buf.writeUtf(!io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions ? "never" : this.collisionRule); // Paper
buf.writeEnum(this.color);
buf.writeComponent(this.playerPrefix);
buf.writeComponent(this.playerSuffix);
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 4b9de3ca81b60eb4a916006cdfbc2a630a390a39..bb8546e5f7f223cb499ab404845aba524726ea16 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -586,6 +586,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(worldserver.getWorld()));
}
+ // Paper start - Handle collideRule team for player collision toggle
+ final ServerScoreboard scoreboard = this.getScoreboard();
+ final java.util.Collection<String> toRemove = scoreboard.getPlayerTeams().stream().filter(team -> team.getName().startsWith("collideRule_")).map(net.minecraft.world.scores.PlayerTeam::getName).collect(java.util.stream.Collectors.toList());
+ for (String teamName : toRemove) {
+ scoreboard.removePlayerTeam(scoreboard.getPlayerTeam(teamName)); // Clean up after ourselves
+ }
+
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().collisions.enablePlayerCollisions) {
+ this.getPlayerList().collideRuleTeamName = org.apache.commons.lang3.StringUtils.left("collideRule_" + java.util.concurrent.ThreadLocalRandom.current().nextInt(), 16);
+ net.minecraft.world.scores.PlayerTeam collideTeam = scoreboard.addPlayerTeam(this.getPlayerList().collideRuleTeamName);
+ collideTeam.setSeeFriendlyInvisibles(false); // Because we want to mimic them not being on a team at all
+ }
+ // Paper end
+
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
this.connection.acceptConnections();
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 9e835d63e1592fc064b73c51eecd8b84cbedfa33..7901a8e3659be05d901fd5140e025392ffa0c27c 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -99,6 +99,7 @@ import net.minecraft.world.level.storage.PlayerDataStorage;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.Objective;
import net.minecraft.world.scores.PlayerTeam;
+import net.minecraft.world.scores.Scoreboard; // Paper
import net.minecraft.world.scores.Team;
import org.slf4j.Logger;
@@ -164,6 +165,7 @@ public abstract class PlayerList {
// CraftBukkit start
private CraftServer cserver;
private final Map<String,ServerPlayer> playersByName = new java.util.HashMap<>();
+ public @Nullable String collideRuleTeamName; // Paper - Team name used for collideRule
public PlayerList(MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registryManager, PlayerDataStorage saveHandler, int maxPlayers) {
this.cserver = server.server = new CraftServer((DedicatedServer) server, this);
@@ -416,6 +418,13 @@ public abstract class PlayerList {
player.initInventoryMenu();
// CraftBukkit - Moved from above, added world
+ // Paper start - Add to collideRule team if needed
+ final Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
+ final PlayerTeam collideRuleTeam = scoreboard.getPlayerTeam(this.collideRuleTeamName);
+ if (this.collideRuleTeamName != null && collideRuleTeam != null && player.getTeam() == null) {
+ scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
+ }
+ // Paper end
PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ());
}
@@ -535,6 +544,16 @@ public abstract class PlayerList {
entityplayer.doTick(); // SPIGOT-924
// CraftBukkit end
+ // Paper start - Remove from collideRule team if needed
+ if (this.collideRuleTeamName != null) {
+ final Scoreboard scoreBoard = this.server.getLevel(Level.OVERWORLD).getScoreboard();
+ final PlayerTeam team = scoreBoard.getPlayersTeam(this.collideRuleTeamName);
+ if (entityplayer.getTeam() == team && team != null) {
+ scoreBoard.removePlayerFromTeam(entityplayer.getScoreboardName(), team);
+ }
+ }
+ // Paper end
+
this.save(entityplayer);
if (entityplayer.isPassenger()) {
Entity entity = entityplayer.getRootVehicle();
@@ -1166,6 +1185,13 @@ public abstract class PlayerList {
}
// CraftBukkit end
+ // Paper start - Remove collideRule team if it exists
+ if (this.collideRuleTeamName != null) {
+ final Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
+ final PlayerTeam team = scoreboard.getPlayersTeam(this.collideRuleTeamName);
+ if (team != null) scoreboard.removePlayerTeam(team);
+ }
+ // Paper end
}
// CraftBukkit start

View file

@ -1,49 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Wed, 13 Apr 2016 20:21:38 -0700
Subject: [PATCH] Add handshake event to allow plugins to handle client
handshaking logic themselves
diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
index 3d08ad662b02812a2b194f95fba55798b9976955..77d7f070cce1a47e41b5d4f5a1cc8c778352a126 100644
--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
@@ -89,9 +89,36 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL
this.connection.disconnect(ichatmutablecomponent);
} else {
this.connection.setListener(new ServerLoginPacketListenerImpl(this.server, this.connection));
+ // Paper start - handshake event
+ boolean proxyLogicEnabled = org.spigotmc.SpigotConfig.bungee;
+ boolean handledByEvent = false;
+ // Try and handle the handshake through the event
+ if (com.destroystokyo.paper.event.player.PlayerHandshakeEvent.getHandlerList().getRegisteredListeners().length != 0) { // Hello? Can you hear me?
+ java.net.SocketAddress socketAddress = this.connection.address;
+ String hostnameOfRemote = socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getHostString() : InetAddress.getLoopbackAddress().getHostAddress();
+ com.destroystokyo.paper.event.player.PlayerHandshakeEvent event = new com.destroystokyo.paper.event.player.PlayerHandshakeEvent(packet.hostName, hostnameOfRemote, !proxyLogicEnabled);
+ if (event.callEvent()) {
+ // If we've failed somehow, let the client know so and go no further.
+ if (event.isFailed()) {
+ Component component = io.papermc.paper.adventure.PaperAdventure.asVanilla(event.failMessage());
+ this.connection.send(new ClientboundLoginDisconnectPacket(component));
+ this.connection.disconnect(component);
+ return;
+ }
+
+ if (event.getServerHostname() != null) packet.hostName = event.getServerHostname();
+ if (event.getSocketAddressHostname() != null) this.connection.address = new java.net.InetSocketAddress(event.getSocketAddressHostname(), socketAddress instanceof java.net.InetSocketAddress ? ((java.net.InetSocketAddress) socketAddress).getPort() : 0);
+ this.connection.spoofedUUID = event.getUniqueId();
+ this.connection.spoofedProfile = gson.fromJson(event.getPropertiesJson(), com.mojang.authlib.properties.Property[].class);
+ handledByEvent = true; // Hooray, we did it!
+ }
+ }
// Spigot Start
String[] split = packet.hostName.split("\00");
- if (org.spigotmc.SpigotConfig.bungee) {
+ // Don't try and handle default logic if it's been handled by the event.
+ if (!handledByEvent && proxyLogicEnabled) {
+ // Paper end
+ // if (org.spigotmc.SpigotConfig.bungee) { // Paper - comment out, we check above!
if ( ( split.length == 3 || split.length == 4 ) && ( ServerHandshakePacketListenerImpl.HOST_PATTERN.matcher( split[1] ).matches() ) ) {
packet.hostName = split[0];
connection.address = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getPort());

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 16 Apr 2016 00:39:33 -0400
Subject: [PATCH] Configurable RCON IP address
For servers with multiple IP's, ability to bind to a specific interface.
== AT ==
public net.minecraft.server.dedicated.Settings getStringRaw(Ljava/lang/String;)Ljava/lang/String;
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
index d2d5a6cd70299c169f50684e442ce90be5840f62..d144fc518442762e45f213550a9b0a21f77fcdd1 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
@@ -108,6 +108,8 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
private final DedicatedServerProperties.WorldDimensionData worldDimensionData;
public final WorldOptions worldOptions;
+ public final String rconIp; // Paper - Add rcon ip
+
// CraftBukkit start
public DedicatedServerProperties(Properties properties, OptionSet optionset) {
super(properties, optionset);
@@ -165,6 +167,10 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
}, WorldPresets.NORMAL.location().toString()));
this.serverResourcePackInfo = DedicatedServerProperties.getServerPackInfo(this.get("resource-pack", ""), this.get("resource-pack-sha1", ""), this.getLegacyString("resource-pack-hash"), this.get("require-resource-pack", false), this.get("resource-pack-prompt", ""));
this.initialDataPackConfiguration = DedicatedServerProperties.getDatapackConfig(this.get("initial-enabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getEnabled())), this.get("initial-disabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getDisabled())));
+ // Paper start - Configurable rcon ip
+ final String rconIp = this.getStringRaw("rcon.ip");
+ this.rconIp = rconIp == null ? this.serverIp : rconIp;
+ // Paper end
}
// CraftBukkit start
diff --git a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
index cb61eaf8447c8340c4b4e1079c0a6aecd41a6116..3bf60f640aa9fa4cabd2b3e5d3931e8467b9df24 100644
--- a/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
+++ b/src/main/java/net/minecraft/server/rcon/thread/RconThread.java
@@ -60,7 +60,7 @@ public class RconThread extends GenericThread {
@Nullable
public static RconThread create(ServerInterface server) {
DedicatedServerProperties dedicatedServerProperties = server.getProperties();
- String string = server.getServerIp();
+ String string = dedicatedServerProperties.rconIp; // Paper - Configurable rcon ip
if (string.isEmpty()) {
string = "0.0.0.0";
}

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Fri, 22 Apr 2016 01:43:11 -0500
Subject: [PATCH] EntityRegainHealthEvent isFastRegen API
Don't even get me started
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 8435d0c62c716d4cce5d8b512d8a42658f774876..d7c437dc575a06e1cdf7b393acaeee6007424687 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1291,10 +1291,16 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) {
+ // Paper start - Forward
+ heal(f, regainReason, false);
+ }
+
+ public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason, boolean isFastRegen) {
+ // Paper end
float f1 = this.getHealth();
if (f1 > 0.0F) {
- EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason);
+ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason, isFastRegen); // Paper
// Suppress during worldgen
if (this.valid) {
this.level().getCraftServer().getPluginManager().callEvent(event);
diff --git a/src/main/java/net/minecraft/world/food/FoodData.java b/src/main/java/net/minecraft/world/food/FoodData.java
index 5ff0eba33f848de5172944274e14062090ab7407..2038df72f8d7d33d4105de8129628daf21de6f0f 100644
--- a/src/main/java/net/minecraft/world/food/FoodData.java
+++ b/src/main/java/net/minecraft/world/food/FoodData.java
@@ -83,7 +83,7 @@ public class FoodData {
if (this.tickTimer >= this.saturatedRegenRate) { // CraftBukkit
float f = Math.min(this.saturationLevel, 6.0F);
- player.heal(f / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED); // CraftBukkit - added RegainReason
+ player.heal(f / 6.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED, true); // CraftBukkit - added RegainReason // Paper - This is fast regen
// this.addExhaustion(f); CraftBukkit - EntityExhaustionEvent
player.causeFoodExhaustion(f, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.REGEN); // CraftBukkit - EntityExhaustionEvent
this.tickTimer = 0;

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Thu, 21 Apr 2016 23:51:55 -0700
Subject: [PATCH] Add ability to configure frosted_ice properties
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 e1916fe8a7aa736d9266efde954bbfbda38a3a65..331b642c36af97f7f05bd63f96d42d1af443e5a3 100644
--- a/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/FrostedIceBlock.java
@@ -32,6 +32,7 @@ public class FrostedIceBlock extends IceBlock {
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ if (!world.paperConfig().environment.frostedIce.enabled) return; // Paper - add ability to disable frosted ice
if ((random.nextInt(3) == 0 || this.fewerNeigboursThan(world, pos, 4)) && world.getMaxLocalRawBrightness(pos) > 11 - state.getValue(AGE) - state.getLightBlock(world, pos) && this.slightlyMelt(state, world, pos)) {
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
@@ -39,12 +40,12 @@ public class FrostedIceBlock extends IceBlock {
mutableBlockPos.setWithOffset(pos, direction);
BlockState blockState = world.getBlockState(mutableBlockPos);
if (blockState.is(this) && !this.slightlyMelt(blockState, world, mutableBlockPos)) {
- world.scheduleTick(mutableBlockPos, this, Mth.nextInt(random, 20, 40));
+ 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
}
}
} else {
- world.scheduleTick(pos, this, Mth.nextInt(random, 20, 40));
+ world.scheduleTick(pos, this, Mth.nextInt(random, world.paperConfig().environment.frostedIce.delay.min, world.paperConfig().environment.frostedIce.delay.max)); // Paper - use configurable min/max delay
}
}

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 28 Apr 2016 00:57:27 -0400
Subject: [PATCH] remove null possibility for getServer singleton
to stop IDE complaining about potential NPE
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index bb8546e5f7f223cb499ab404845aba524726ea16..0ee486f807d7c44e2252c4c744e29b506d916d9c 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -193,6 +193,7 @@ import co.aikar.timings.MinecraftTimings; // Paper
public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements CommandSource, AutoCloseable {
+ private static MinecraftServer SERVER; // Paper
public static final Logger LOGGER = LogUtils.getLogger();
public static final net.kyori.adventure.text.logger.slf4j.ComponentLogger COMPONENT_LOGGER = net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(LOGGER.getName()); // Paper
public static final String VANILLA_BRAND = "vanilla";
@@ -319,6 +320,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public MinecraftServer(OptionSet options, WorldLoader.DataLoadContext worldLoader, Thread thread, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PackRepository resourcepackrepository, WorldStem worldstem, Proxy proxy, DataFixer datafixer, Services services, ChunkProgressListenerFactory worldloadlistenerfactory) {
super("Server");
+ SERVER = this; // Paper - better singleton
this.metricsRecorder = InactiveMetricsRecorder.INSTANCE;
this.profiler = this.metricsRecorder.getProfiler();
this.onMetricsRecordingStopped = (methodprofilerresults) -> {
@@ -2323,9 +2325,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return false;
}
- @Deprecated
public static MinecraftServer getServer() {
- return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null;
+ return SERVER; // Paper
}
// CraftBukkit end

View file

@ -1,128 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 29 Apr 2016 20:02:00 -0400
Subject: [PATCH] Improve Maps (in item frames) performance and bug fixes
Maps used a modified version of rendering to support plugin controlled
imaging on maps. The Craft Map Renderer is much slower than Vanilla,
causing maps in item frames to cause a noticeable hit on server performance.
This updates the map system to not use the Craft system if we detect that no
custom renderers are in use, defaulting to the much simpler Vanilla system.
Additionally, numerous issues to player position tracking on maps has been fixed.
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 35b59c83a35bc3a4d05bc95b0caec1f1865589c0..17d9c5a6c357ac5e3eacd9e4d2cff9a05ec0f262 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -2394,6 +2394,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
{
if ( iter.next().player == entity )
{
+ map.decorations.remove(entity.getName().getString()); // Paper
iter.remove();
}
}
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 c20753645585143421eb544a03884f0765eafb8b..11e7c30e448f192493c65330a65d89ed3e14139f 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -763,6 +763,14 @@ public abstract class Player extends LivingEntity {
return null;
}
// CraftBukkit end
+ // Paper start - remove player from map on drop
+ if (itemstack.getItem() == Items.FILLED_MAP) {
+ net.minecraft.world.level.saveddata.maps.MapItemSavedData worldmap = net.minecraft.world.item.MapItem.getSavedData(itemstack, this.level());
+ if (worldmap != null) {
+ worldmap.tickCarriedBy(this, itemstack);
+ }
+ }
+ // Paper end
return entityitem;
}
diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
index 60596c4ac2ebb8caf19d65591624275ba63b0199..d6ed799716f13cb3f72e66f9d57c6ec90c1eb272 100644
--- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -63,6 +63,7 @@ public class MapItemSavedData extends SavedData {
public final Map<String, MapDecoration> decorations = Maps.newLinkedHashMap();
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
private int trackedDecorationCount;
+ private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper
// CraftBukkit start
public final CraftMapView mapView;
@@ -83,6 +84,7 @@ public class MapItemSavedData extends SavedData {
// CraftBukkit start
this.mapView = new CraftMapView(this);
this.server = (CraftServer) org.bukkit.Bukkit.getServer();
+ this.vanillaRender.buffer = colors; // Paper
// CraftBukkit end
}
@@ -138,6 +140,7 @@ public class MapItemSavedData extends SavedData {
if (abyte.length == 16384) {
worldmap.colors = abyte;
}
+ worldmap.vanillaRender.buffer = abyte; // Paper
ListTag nbttaglist = nbt.getList("banners", 10);
@@ -548,6 +551,21 @@ public class MapItemSavedData extends SavedData {
public class HoldingPlayer {
+ // Paper start
+ private void addSeenPlayers(java.util.Collection<MapDecoration> icons) {
+ org.bukkit.entity.Player player = (org.bukkit.entity.Player) this.player.getBukkitEntity();
+ MapItemSavedData.this.decorations.forEach((name, mapIcon) -> {
+ // If this cursor is for a player check visibility with vanish system
+ org.bukkit.entity.Player other = org.bukkit.Bukkit.getPlayerExact(name); // Spigot
+ if (other == null || player.canSee(other)) {
+ icons.add(mapIcon);
+ }
+ });
+ }
+ private boolean shouldUseVanillaMap() {
+ return mapView.getRenderers().size() == 1 && mapView.getRenderers().get(0).getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class;
+ }
+ // Paper end
public final Player player;
private boolean dirtyData = true;
private int minDirtyX;
@@ -581,7 +599,9 @@ public class MapItemSavedData extends SavedData {
@Nullable
Packet<?> nextUpdatePacket(int mapId) {
MapItemSavedData.MapPatch worldmap_b;
- org.bukkit.craftbukkit.map.RenderData render = MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()); // CraftBukkit
+ if (!this.dirtyData && this.tick % 5 != 0) { this.tick++; return null; } // Paper - this won't end up sending, so don't render it!
+ boolean vanillaMaps = shouldUseVanillaMap(); // Paper
+ org.bukkit.craftbukkit.map.RenderData render = !vanillaMaps ? MapItemSavedData.this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) this.player.getBukkitEntity()) : MapItemSavedData.this.vanillaRender; // CraftBukkit // Paper
if (this.dirtyData) {
this.dirtyData = false;
@@ -597,6 +617,8 @@ public class MapItemSavedData extends SavedData {
// CraftBukkit start
java.util.Collection<MapDecoration> icons = new java.util.ArrayList<MapDecoration>();
+ if (vanillaMaps) addSeenPlayers(icons); // Paper
+
for (org.bukkit.map.MapCursor cursor : render.cursors) {
if (cursor.isVisible()) {
icons.add(new MapDecoration(MapDecoration.Type.byIcon(cursor.getRawType()), cursor.getX(), cursor.getY(), cursor.getDirection(), PaperAdventure.asVanilla(cursor.caption()))); // Paper - Adventure
diff --git a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java
index 256a131781721c86dd6cdbc329335964570cbe8c..5768cd512ec166f1e8d1f4a28792015347297c3f 100644
--- a/src/main/java/org/bukkit/craftbukkit/map/RenderData.java
+++ b/src/main/java/org/bukkit/craftbukkit/map/RenderData.java
@@ -5,7 +5,7 @@ import org.bukkit.map.MapCursor;
public class RenderData {
- public final byte[] buffer;
+ public byte[] buffer; // Paper
public final ArrayList<MapCursor> cursors;
public RenderData() {

View file

@ -1,800 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 1 May 2016 21:19:14 -0400
Subject: [PATCH] LootTable API & Replenishable Lootables Feature
Provides an API to control the loot table for an object.
Also provides a feature that any Lootable Inventory (Chests in Structures)
can automatically replenish after a given time.
This feature is good for long term worlds so that newer players
do not suffer with "Every chest has been looted"
== AT ==
public org.bukkit.craftbukkit.block.CraftBlockEntityState getTileEntity()Lnet/minecraft/world/level/block/entity/BlockEntity;
public org.bukkit.craftbukkit.block.CraftLootable setLootTable(Lorg/bukkit/loot/LootTable;J)V
public org.bukkit.craftbukkit.entity.CraftMinecartContainer setLootTable(Lorg/bukkit/loot/LootTable;J)V
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ca389ca789dc54bba3542cac0aac2e1dc66c870
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
@@ -0,0 +1,63 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.vehicle.AbstractMinecartContainer;
+import net.minecraft.world.entity.vehicle.ContainerEntity;
+import net.minecraft.world.level.Level;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+
+public class PaperContainerEntityLootableInventory implements PaperLootableEntityInventory {
+
+ private final ContainerEntity entity;
+
+ public PaperContainerEntityLootableInventory(ContainerEntity entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public org.bukkit.loot.LootTable getLootTable() {
+ return entity.getLootTable() != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null;
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
+ setLootTable(table);
+ setSeed(seed);
+ }
+
+ @Override
+ public void setSeed(long seed) {
+ entity.setLootTableSeed(seed);
+ }
+
+ @Override
+ public long getSeed() {
+ return entity.getLootTableSeed();
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table) {
+ entity.setLootTable((table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey()));
+ }
+
+ @Override
+ public PaperLootableInventoryData getLootableData() {
+ return entity.getLootableData();
+ }
+
+ @Override
+ public Entity getHandle() {
+ return entity.getEntity();
+ }
+
+ @Override
+ public LootableInventory getAPILootableInventory() {
+ return (LootableInventory) entity.getEntity().getBukkitEntity();
+ }
+
+ @Override
+ public Level getNMSWorld() {
+ return entity.level();
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..24c6ff57cd25533e71f8a1d0b3c0ece2fdbbf87e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
@@ -0,0 +1,33 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
+import org.bukkit.Chunk;
+import org.bukkit.block.Block;
+
+public interface PaperLootableBlockInventory extends LootableBlockInventory, PaperLootableInventory {
+
+ RandomizableContainerBlockEntity getTileEntity();
+
+ @Override
+ default LootableInventory getAPILootableInventory() {
+ return this;
+ }
+
+ @Override
+ default Level getNMSWorld() {
+ return this.getTileEntity().getLevel();
+ }
+
+ default Block getBlock() {
+ final BlockPos position = this.getTileEntity().getBlockPos();
+ final Chunk bukkitChunk = this.getBukkitWorld().getChunkAt(org.bukkit.craftbukkit.block.CraftBlock.at(this.getNMSWorld(), position));
+ return bukkitChunk.getBlock(position.getX(), position.getY(), position.getZ());
+ }
+
+ @Override
+ default PaperLootableInventoryData getLootableData() {
+ return this.getTileEntity().lootableData;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..2fba5bc0f982e143ad5f5bda55d768edc5f847df
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
@@ -0,0 +1,28 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.world.level.Level;
+import org.bukkit.entity.Entity;
+
+public interface PaperLootableEntityInventory extends LootableEntityInventory, PaperLootableInventory {
+
+ net.minecraft.world.entity.Entity getHandle();
+
+ @Override
+ default LootableInventory getAPILootableInventory() {
+ return this;
+ }
+
+ default Entity getEntity() {
+ return getHandle().getBukkitEntity();
+ }
+
+ @Override
+ default Level getNMSWorld() {
+ return getHandle().getCommandSenderWorld();
+ }
+
+ @Override
+ default PaperLootableInventoryData getLootableData() {
+ return getHandle().lootableData;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e6dac2cef7af26ad74928eff631c1826c2980bb
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
@@ -0,0 +1,75 @@
+package com.destroystokyo.paper.loottable;
+
+import org.bukkit.loot.Lootable;
+import java.util.UUID;
+import net.minecraft.world.level.Level;
+
+public interface PaperLootableInventory extends LootableInventory, Lootable {
+
+ PaperLootableInventoryData getLootableData();
+ LootableInventory getAPILootableInventory();
+
+ Level getNMSWorld();
+
+ default org.bukkit.World getBukkitWorld() {
+ return getNMSWorld().getWorld();
+ }
+
+ @Override
+ default boolean isRefillEnabled() {
+ return getNMSWorld().paperConfig().lootables.autoReplenish;
+ }
+
+ @Override
+ default boolean hasBeenFilled() {
+ return getLastFilled() != -1;
+ }
+
+ @Override
+ default boolean hasPlayerLooted(UUID player) {
+ return getLootableData().hasPlayerLooted(player);
+ }
+
+ @Override
+ default boolean canPlayerLoot(final UUID player) {
+ return getLootableData().canPlayerLoot(player, this.getNMSWorld().paperConfig());
+ }
+
+ @Override
+ default Long getLastLooted(UUID player) {
+ return getLootableData().getLastLooted(player);
+ }
+
+ @Override
+ default boolean setHasPlayerLooted(UUID player, boolean looted) {
+ final boolean hasLooted = hasPlayerLooted(player);
+ if (hasLooted != looted) {
+ getLootableData().setPlayerLootedState(player, looted);
+ }
+ return hasLooted;
+ }
+
+ @Override
+ default boolean hasPendingRefill() {
+ long nextRefill = getLootableData().getNextRefill();
+ return nextRefill != -1 && nextRefill > getLootableData().getLastFill();
+ }
+
+ @Override
+ default long getLastFilled() {
+ return getLootableData().getLastFill();
+ }
+
+ @Override
+ default long getNextRefill() {
+ return getLootableData().getNextRefill();
+ }
+
+ @Override
+ default long setNextRefill(long refillAt) {
+ if (refillAt < -1) {
+ refillAt = -1;
+ }
+ return getLootableData().setNextRefill(refillAt);
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
new file mode 100644
index 0000000000000000000000000000000000000000..5408cbc21fc7577a6100b5a1ca0463e899d2df8b
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
@@ -0,0 +1,188 @@
+package com.destroystokyo.paper.loottable;
+
+import io.papermc.paper.configuration.WorldConfiguration;
+import io.papermc.paper.configuration.type.DurationOrDisabled;
+import java.time.temporal.ChronoUnit;
+import java.util.concurrent.TimeUnit;
+import org.bukkit.entity.Player;
+import org.bukkit.loot.LootTable;
+import javax.annotation.Nullable;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.ListTag;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
+
+public class PaperLootableInventoryData {
+
+ private static final Random RANDOM = new Random();
+
+ private long lastFill = -1;
+ private long nextRefill = -1;
+ private int numRefills = 0;
+ private Map<UUID, Long> lootedPlayers;
+ private final PaperLootableInventory lootable;
+
+ public PaperLootableInventoryData(PaperLootableInventory lootable) {
+ this.lootable = lootable;
+ }
+
+ long getLastFill() {
+ return this.lastFill;
+ }
+
+ long getNextRefill() {
+ return this.nextRefill;
+ }
+
+ long setNextRefill(long nextRefill) {
+ long prev = this.nextRefill;
+ this.nextRefill = nextRefill;
+ return prev;
+ }
+
+ public boolean shouldReplenish(@Nullable net.minecraft.world.entity.player.Player player) {
+ LootTable table = this.lootable.getLootTable();
+
+ // No Loot Table associated
+ if (table == null) {
+ return false;
+ }
+
+ // ALWAYS process the first fill or if the feature is disabled
+ if (this.lastFill == -1 || !this.lootable.getNMSWorld().paperConfig().lootables.autoReplenish) {
+ return true;
+ }
+
+ // Only process refills when a player is set
+ if (player == null) {
+ return false;
+ }
+
+ // Chest is not scheduled for refill
+ if (this.nextRefill == -1) {
+ return false;
+ }
+
+ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig();
+
+ // Check if max refills has been hit
+ if (paperConfig.lootables.maxRefills != -1 && this.numRefills >= paperConfig.lootables.maxRefills) {
+ return false;
+ }
+
+ // Refill has not been reached
+ if (this.nextRefill > System.currentTimeMillis()) {
+ return false;
+ }
+
+
+ final Player bukkitPlayer = (Player) player.getBukkitEntity();
+ LootableInventoryReplenishEvent event = new LootableInventoryReplenishEvent(bukkitPlayer, lootable.getAPILootableInventory());
+ event.setCancelled(!canPlayerLoot(player.getUUID(), paperConfig));
+ return event.callEvent();
+ }
+ public void processRefill(@Nullable net.minecraft.world.entity.player.Player player) {
+ this.lastFill = System.currentTimeMillis();
+ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig();
+ if (paperConfig.lootables.autoReplenish) {
+ long min = paperConfig.lootables.refreshMin.seconds();
+ long max = paperConfig.lootables.refreshMax.seconds();
+ this.nextRefill = this.lastFill + (min + RANDOM.nextLong(max - min + 1)) * 1000L;
+ this.numRefills++;
+ if (paperConfig.lootables.resetSeedOnFill) {
+ this.lootable.setSeed(0);
+ }
+ if (player != null) { // This means that numRefills can be incremented without a player being in the lootedPlayers list - Seems to be EntityMinecartChest specific
+ this.setPlayerLootedState(player.getUUID(), true);
+ }
+ } else {
+ this.lootable.clearLootTable();
+ }
+ }
+
+
+ public void loadNbt(CompoundTag base) {
+ if (!base.contains("Paper.LootableData", 10)) { // 10 = compound
+ return;
+ }
+ CompoundTag comp = base.getCompound("Paper.LootableData");
+ if (comp.contains("lastFill")) {
+ this.lastFill = comp.getLong("lastFill");
+ }
+ if (comp.contains("nextRefill")) {
+ this.nextRefill = comp.getLong("nextRefill");
+ }
+
+ if (comp.contains("numRefills")) {
+ this.numRefills = comp.getInt("numRefills");
+ }
+ if (comp.contains("lootedPlayers", 9)) { // 9 = list
+ ListTag list = comp.getList("lootedPlayers", 10); // 10 = compound
+ final int size = list.size();
+ if (size > 0) {
+ this.lootedPlayers = new HashMap<>(list.size());
+ }
+ for (int i = 0; i < size; i++) {
+ final CompoundTag cmp = list.getCompound(i);
+ lootedPlayers.put(cmp.getUUID("UUID"), cmp.getLong("Time"));
+ }
+ }
+ }
+ public void saveNbt(CompoundTag base) {
+ CompoundTag comp = new CompoundTag();
+ if (this.nextRefill != -1) {
+ comp.putLong("nextRefill", this.nextRefill);
+ }
+ if (this.lastFill != -1) {
+ comp.putLong("lastFill", this.lastFill);
+ }
+ if (this.numRefills != 0) {
+ comp.putInt("numRefills", this.numRefills);
+ }
+ if (this.lootedPlayers != null && !this.lootedPlayers.isEmpty()) {
+ ListTag list = new ListTag();
+ for (Map.Entry<UUID, Long> entry : this.lootedPlayers.entrySet()) {
+ CompoundTag cmp = new CompoundTag();
+ cmp.putUUID("UUID", entry.getKey());
+ cmp.putLong("Time", entry.getValue());
+ list.add(cmp);
+ }
+ comp.put("lootedPlayers", list);
+ }
+
+ if (!comp.isEmpty()) {
+ base.put("Paper.LootableData", comp);
+ }
+ }
+
+ void setPlayerLootedState(UUID player, boolean looted) {
+ if (looted && this.lootedPlayers == null) {
+ this.lootedPlayers = new HashMap<>();
+ }
+ if (looted) {
+ this.lootedPlayers.put(player, System.currentTimeMillis());
+ } else if (this.lootedPlayers != null) {
+ this.lootedPlayers.remove(player);
+ }
+ }
+
+ boolean canPlayerLoot(final UUID player, final WorldConfiguration worldConfiguration) {
+ final Long lastLooted = getLastLooted(player);
+ if (!worldConfiguration.lootables.restrictPlayerReloot || lastLooted == null) return true;
+
+ final DurationOrDisabled restrictPlayerRelootTime = worldConfiguration.lootables.restrictPlayerRelootTime;
+ if (restrictPlayerRelootTime.value().isEmpty()) return false;
+
+ return TimeUnit.SECONDS.toMillis(restrictPlayerRelootTime.value().get().seconds()) + lastLooted < System.currentTimeMillis();
+ }
+
+ boolean hasPlayerLooted(UUID player) {
+ return this.lootedPlayers != null && this.lootedPlayers.containsKey(player);
+ }
+
+ Long getLastLooted(UUID player) {
+ return lootedPlayers != null ? lootedPlayers.get(player) : null;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cfa5d36a6991067a3866e0d437749fafcc0158e
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
@@ -0,0 +1,65 @@
+package com.destroystokyo.paper.loottable;
+
+import io.papermc.paper.util.MCUtil;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+
+public class PaperTileEntityLootableInventory implements PaperLootableBlockInventory {
+ private RandomizableContainerBlockEntity tileEntityLootable;
+
+ public PaperTileEntityLootableInventory(RandomizableContainerBlockEntity tileEntityLootable) {
+ this.tileEntityLootable = tileEntityLootable;
+ }
+
+ @Override
+ public org.bukkit.loot.LootTable getLootTable() {
+ return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
+ setLootTable(table);
+ setSeed(seed);
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table) {
+ tileEntityLootable.lootTable = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
+ }
+
+ @Override
+ public void setSeed(long seed) {
+ tileEntityLootable.lootTableSeed = seed;
+ }
+
+ @Override
+ public long getSeed() {
+ return tileEntityLootable.lootTableSeed;
+ }
+
+ @Override
+ public PaperLootableInventoryData getLootableData() {
+ return tileEntityLootable.lootableData;
+ }
+
+ @Override
+ public RandomizableContainerBlockEntity getTileEntity() {
+ return tileEntityLootable;
+ }
+
+ @Override
+ public LootableInventory getAPILootableInventory() {
+ Level world = tileEntityLootable.getLevel();
+ if (world == null) {
+ return null;
+ }
+ return (LootableInventory) getBukkitWorld().getBlockAt(MCUtil.toLocation(world, tileEntityLootable.getBlockPos())).getState();
+ }
+
+ @Override
+ public Level getNMSWorld() {
+ return tileEntityLootable.getLevel();
+ }
+}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 2f15c9df59ebfbe7619e190b8d6ef1fe122809f8..069fe5df02806103c9bbef396c2e39ca3be90101 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -235,6 +235,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
// Paper end
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
private CraftEntity bukkitEntity;
public CraftEntity getBukkitEntity() {
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
index 0ec2db500e4a0230a91286a709b8d444d1b529f4..272095d7a09ab41227d741172735f66fd2798ce1 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
@@ -32,6 +32,20 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
public ResourceLocation lootTable;
public long lootTableSeed;
+ // Paper start
+ {
+ this.lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperContainerEntityLootableInventory(this));
+ }
+ @Override
+ public Entity getEntity() {
+ return this;
+ }
+
+ @Override
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ return this.lootableData;
+ }
+ // Paper end
// CraftBukkit start
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
@@ -134,12 +148,14 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
@Override
protected void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
+ this.lootableData.saveNbt(nbt); // Paper
this.addChestVehicleSaveData(nbt);
}
@Override
protected void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
+ this.lootableData.loadNbt(nbt); // Paper
this.readChestVehicleSaveData(nbt);
}
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
index d88a6501917306eab57f46cb0d10dc03164a94da..e88c39d405fc7068db64ad34a03dec8d559e749e 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
@@ -65,12 +65,14 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
@Override
protected void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
+ this.lootableData.saveNbt(nbt); // Paper
this.addChestVehicleSaveData(nbt);
}
@Override
protected void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
+ this.lootableData.loadNbt(nbt); // Paper
this.readChestVehicleSaveData(nbt);
}
@@ -245,6 +247,20 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
this.level().gameEvent(GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of((Entity) player));
}
+ // Paper start
+ {
+ this.lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperContainerEntityLootableInventory(this));
+ }
+ @Override
+ public Entity getEntity() {
+ return this;
+ }
+
+ @Override
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ return this.lootableData;
+ }
+ // Paper end
// CraftBukkit start
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
index e0fbacd574e0c83c2e1d164ded8e9ccf4af30480..7529751afa2932fd16bc4591189b0358268a7b14 100644
--- a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
@@ -59,10 +59,9 @@ public interface ContainerEntity extends Container, MenuProvider {
if (this.getLootTableSeed() != 0L) {
nbt.putLong("LootTableSeed", this.getLootTableSeed());
}
- } else {
- ContainerHelper.saveAllItems(nbt, this.getItemStacks());
}
+ ContainerHelper.saveAllItems(nbt, this.getItemStacks()); // Paper - always save the items, table may still remain
}
default void readChestVehicleSaveData(CompoundTag nbt) {
@@ -70,10 +69,9 @@ public interface ContainerEntity extends Container, MenuProvider {
if (nbt.contains("LootTable", 8)) {
this.setLootTable(new ResourceLocation(nbt.getString("LootTable")));
this.setLootTableSeed(nbt.getLong("LootTableSeed"));
- } else {
- ContainerHelper.loadAllItems(nbt, this.getItemStacks());
}
+ ContainerHelper.loadAllItems(nbt, this.getItemStacks()); // Paper - always load the items, table may still remain
}
default void chestVehicleDestroyed(DamageSource source, Level world, Entity vehicle) {
@@ -96,13 +94,13 @@ public interface ContainerEntity extends Container, MenuProvider {
default void unpackChestVehicleLootTable(@Nullable Player player) {
MinecraftServer minecraftServer = this.level().getServer();
- if (this.getLootTable() != null && minecraftServer != null) {
+ if (this.getLootableData().shouldReplenish(player) && minecraftServer != null) { // Paper
LootTable lootTable = minecraftServer.getLootData().getLootTable(this.getLootTable());
if (player != null) {
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, this.getLootTable());
}
- this.setLootTable((ResourceLocation)null);
+ this.getLootableData().processRefill(player); // Paper
LootParams.Builder builder = (new LootParams.Builder((ServerLevel)this.level())).withParameter(LootContextParams.ORIGIN, this.position());
if (player != null) {
builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player);
@@ -176,4 +174,13 @@ public interface ContainerEntity extends Container, MenuProvider {
default boolean isChestVehicleStillValid(Player player) {
return !this.isRemoved() && this.position().closerThan(player.position(), 8.0D);
}
+ // Paper start
+ default Entity getEntity() {
+ throw new UnsupportedOperationException();
+ }
+
+ default com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ throw new UnsupportedOperationException();
+ }
+ // Paper end
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
index 111494c30a2b7d8464237a92cf5c98f7f4cca19d..e11618247ad889fa8fadbb2c7addd0de94caf249 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
@@ -29,6 +29,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
@Nullable
public ResourceLocation lootTable;
public long lootTableSeed;
+ public final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperTileEntityLootableInventory(this)); // Paper
protected RandomizableContainerBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
@@ -43,16 +44,19 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
}
protected boolean tryLoadLootTable(CompoundTag nbt) {
+ this.lootableData.loadNbt(nbt); // Paper
if (nbt.contains("LootTable", 8)) {
this.lootTable = new ResourceLocation(nbt.getString("LootTable"));
+ try { org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.lootTable); } catch (IllegalArgumentException ex) { this.lootTable = null; } // Paper - validate
this.lootTableSeed = nbt.getLong("LootTableSeed");
- return true;
+ return false; // Paper - always load the items, table may still remain
} else {
return false;
}
}
protected boolean trySaveLootTable(CompoundTag nbt) {
+ this.lootableData.saveNbt(nbt); // Paper
if (this.lootTable == null) {
return false;
} else {
@@ -61,18 +65,18 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
nbt.putLong("LootTableSeed", this.lootTableSeed);
}
- return true;
+ return false; // Paper - always save the items, table may still remain
}
}
public void unpackLootTable(@Nullable Player player) {
- if (this.lootTable != null && this.level.getServer() != null) {
+ if (this.lootableData.shouldReplenish(player) && this.level.getServer() != null) { // Paper
LootTable lootTable = this.level.getServer().getLootData().getLootTable(this.lootTable);
if (player instanceof ServerPlayer) {
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, this.lootTable);
}
- this.lootTable = null;
+ this.lootableData.processRefill(player); // Paper
LootParams.Builder builder = (new LootParams.Builder((ServerLevel)this.level)).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(this.worldPosition));
if (player != null) {
builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
index d5bfa06a90158fb6d9cc54f7a9b44a277f2c480f..dbdf9b009a488767bb63b0867943fd932fac16e4 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
@@ -60,7 +60,7 @@ public class CraftBrushableBlock extends CraftBlockEntityState<BrushableBlockEnt
this.setLootTable(this.getLootTable(), seed);
}
- private void setLootTable(LootTable table, long seed) {
+ public void setLootTable(LootTable table, long seed) { // Paper - make public since it overrides a public method
ResourceLocation key = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
getSnapshot().setLootTable(key, seed);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
index b31fa63019822bc172d85427b3f3f2c154d7e179..82b3f3b3aced73ce136b6b94fe212972ac6090ef 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
@@ -12,8 +12,9 @@ import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest;
import org.bukkit.inventory.Inventory;
+import com.destroystokyo.paper.loottable.PaperLootableBlockInventory; // Paper
-public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest {
+public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest, PaperLootableBlockInventory { // Paper
public CraftChest(World world, ChestBlockEntity tileEntity) {
super(world, tileEntity);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
index 982adacb361b0590799dc68f9b7c13c7195627fd..e49eece9bff3a53469673d03a7bbf8f9cf8776b8 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
@@ -9,7 +9,7 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.loot.LootTable;
import org.bukkit.loot.Lootable;
-public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable {
+public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable, com.destroystokyo.paper.loottable.PaperLootableBlockInventory { // Paper
public CraftLootable(World world, T tileEntity) {
super(world, tileEntity);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
index 9ba61f791c0ca9b283c0f1f30f12600c4e49a4cb..c332e8504b96a4437325b5a64430c97c5afb6b4b 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
@@ -10,8 +10,7 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.inventory.Inventory;
import org.bukkit.loot.LootTable;
-public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat {
-
+public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final Inventory inventory;
public CraftChestBoat(CraftServer server, ChestBoat entity) {
@@ -60,7 +59,7 @@ public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.Chest
return this.getHandle().getLootTableSeed();
}
- private void setLootTable(LootTable table, long seed) {
+ public void setLootTable(LootTable table, long seed) { // Paper - change visibility since it overrides a public method
ResourceLocation newKey = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
this.getHandle().setLootTable(newKey);
this.getHandle().setLootTableSeed(seed);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
index fd42f0b20132d08039ca7735d31a61806a6b07dc..b1a708de6790bbe336202b13ab862ced78de084f 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
@@ -7,7 +7,7 @@ import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.inventory.Inventory;
@SuppressWarnings("deprecation")
-public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart {
+public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final CraftInventory inventory;
public CraftMinecartChest(CraftServer server, MinecartChest entity) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
index ec3ab12442b7371e16059b902f71e573f0bc9816..3ba7e8ef1035e1de2c195b6919fe57aee398af51 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
@@ -6,7 +6,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.inventory.Inventory;
-public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart {
+public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final CraftInventory inventory;
public CraftMinecartHopper(CraftServer server, MinecartHopper entity) {

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 7 May 2016 23:33:08 -0400
Subject: [PATCH] Don't save empty scoreboard teams to scoreboard.dat
diff --git a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java b/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
index b837b6616a2384b253cca8ed62c9488b639f6298..2be7a697f08045b974579e6942b38571e744efac 100644
--- a/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
+++ b/src/main/java/net/minecraft/world/scores/ScoreboardSaveData.java
@@ -136,6 +136,7 @@ public class ScoreboardSaveData extends SavedData {
ListTag listTag = new ListTag();
for(PlayerTeam playerTeam : this.scoreboard.getPlayerTeams()) {
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().scoreboards.saveEmptyScoreboardTeams && playerTeam.getPlayers().isEmpty()) continue; // Paper
CompoundTag compoundTag = new CompoundTag();
compoundTag.putString("Name", playerTeam.getName());
compoundTag.putString("DisplayName", Component.Serializer.toJson(playerTeam.getDisplayName()));

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Thu, 12 May 2016 23:02:58 -0500
Subject: [PATCH] System property for disabling watchdoge
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index 3ad14bf0697e682a2e777baa8faeb323d127fb13..a9897c494b3dc56d900356d74030359832febbaa 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -61,7 +61,7 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa
while ( !this.stopping )
{
//
- if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.monotonicMillis() > this.lastTick + this.timeoutTime )
+ if ( this.lastTick != 0 && this.timeoutTime > 0 && WatchdogThread.monotonicMillis() > this.lastTick + this.timeoutTime && !Boolean.getBoolean("disable.watchdog")) // Paper - Add property to disable
{
Logger log = Bukkit.getServer().getLogger();
log.log( Level.SEVERE, "------------------------------" );

View file

@ -1,86 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 16 May 2016 20:47:41 -0400
Subject: [PATCH] Async GameProfileCache saving
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 0ee486f807d7c44e2252c4c744e29b506d916d9c..b5ededfb23980abca01ef25207cca95ad390a70d 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -932,7 +932,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
} catch (java.lang.InterruptedException ignored) {} // Paper
if (org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) {
MinecraftServer.LOGGER.info("Saving usercache.json");
- this.getProfileCache().save();
+ this.getProfileCache().save(false); // Paper
}
// Spigot end
io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 6f543665b5ed42eaec6a410fa11f5a38da707110..52c2333afdb3748ffdbcc58ae7629aa2c4b49b74 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -242,7 +242,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
}
if (this.convertOldUsers()) {
- this.getProfileCache().save();
+ this.getProfileCache().save(false); // Paper
}
if (!OldUsersConverter.serverReadyAfterUserconversion(this)) {
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
index d246563021c32127e570809f4d849b6a156f4dc6..225e15d686675e21969c4210fa38fef58d920355 100644
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
@@ -127,7 +127,7 @@ public class GameProfileCache {
GameProfileCache.GameProfileInfo usercache_usercacheentry = new GameProfileCache.GameProfileInfo(profile, date);
this.safeAdd(usercache_usercacheentry);
- if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(); // Spigot - skip saving if disabled
+ if( !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly ) this.save(true); // Spigot - skip saving if disabled // Paper - async
}
private long getNextOperation() {
@@ -160,7 +160,7 @@ public class GameProfileCache {
}
if (flag && !org.spigotmc.SpigotConfig.saveUserCacheOnStopOnly) { // Spigot - skip saving if disabled
- this.save();
+ this.save(true); // Paper
}
return optional;
@@ -274,7 +274,7 @@ public class GameProfileCache {
return arraylist;
}
- public void save() {
+ public void save(boolean asyncSave) { // Paper
JsonArray jsonarray = new JsonArray();
DateFormat dateformat = GameProfileCache.createDateFormat();
@@ -282,6 +282,7 @@ public class GameProfileCache {
jsonarray.add(GameProfileCache.writeGameProfile(usercache_usercacheentry, dateformat));
});
String s = this.gson.toJson(jsonarray);
+ Runnable save = () -> { // Paper
try {
BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8);
@@ -306,6 +307,14 @@ public class GameProfileCache {
} catch (IOException ioexception) {
;
}
+ // Paper start
+ };
+ if (asyncSave) {
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(save);
+ } else {
+ save.run();
+ }
+ // Paper end
}

View file

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sun, 22 May 2016 20:20:55 -0500
Subject: [PATCH] Optional TNT doesn't move in water
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index c6660cc77dfa3c3750b6b4dde5617f00c9de1e0a..ae3d1077b42fb288938a8a65471f00b3f52cb18f 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -70,7 +70,7 @@ public class ServerEntity {
@Nullable
private List<SynchedEntityData.DataValue<?>> trackedDataValues;
// CraftBukkit start
- private final Set<ServerPlayerConnection> trackedPlayers;
+ final Set<ServerPlayerConnection> trackedPlayers; // Paper - private -> package
public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer<Packet<?>> consumer, Set<ServerPlayerConnection> trackedPlayers) {
this.trackedPlayers = trackedPlayers;
diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
index 89fd5d6b373d2705dccc2f22663048f4c2aaa60f..57f9bf73ee14bc8811d0192543caf2b02e890ee0 100644
--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java
@@ -98,6 +98,27 @@ public class PrimedTnt extends Entity implements TraceableEntity {
}
}
+ // Paper start - Optional prevent TNT from moving in water
+ if (!this.isRemoved() && this.wasTouchingWater && this.level().paperConfig().fixes.preventTntFromMovingInWater) {
+ /*
+ * Author: Jedediah Smith <jedediah@silencegreys.com>
+ */
+ // Send position and velocity updates to nearby players on every tick while the TNT is in water.
+ // This does pretty well at keeping their clients in sync with the server.
+ net.minecraft.server.level.ChunkMap.TrackedEntity ete = ((net.minecraft.server.level.ServerLevel)this.level()).getChunkSource().chunkMap.entityMap.get(this.getId());
+ if (ete != null) {
+ net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket velocityPacket = new net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket(this);
+ net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket positionPacket = new net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket(this);
+
+ ete.seenBy.stream()
+ .filter(viewer -> (viewer.getPlayer().getX() - this.getX()) * (viewer.getPlayer().getY() - this.getY()) * (viewer.getPlayer().getZ() - this.getZ()) < 16 * 16)
+ .forEach(viewer -> {
+ viewer.send(velocityPacket);
+ viewer.send(positionPacket);
+ });
+ }
+ }
+ // Paper end
}
private void explode() {
@@ -147,4 +168,11 @@ public class PrimedTnt extends Entity implements TraceableEntity {
public int getFuse() {
return (Integer) this.entityData.get(PrimedTnt.DATA_FUSE_ID);
}
+
+ // Paper start - Optional prevent TNT from moving in water
+ @Override
+ public boolean isPushedByFluid() {
+ return !level().paperConfig().fixes.preventTntFromMovingInWater && super.isPushedByFluid();
+ }
+ // Paper end
}

View file

@ -1,81 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Panzer <postremus1996@googlemail.com>
Date: Mon, 23 May 2016 12:12:37 +0200
Subject: [PATCH] Faster redstone torch rapid clock removal
Only resize the the redstone torch list once, since resizing arrays / lists is costly
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index ba7760b0b478c6f24dcbaa64919a4766e107a720..0c6384c6332babf8e517503c2e9b21a9d6e2ed88 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -173,6 +173,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
+ public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
public CraftWorld getWorld() {
return this.world;
diff --git a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
index 9b6f8508d16bcecd9dc148f75598655e3585f175..da07fce0cf7c9fbdb57d2c59e431b59bf583bf50 100644
--- a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java
@@ -21,7 +21,7 @@ import org.bukkit.event.block.BlockRedstoneEvent; // CraftBukkit
public class RedstoneTorchBlock extends TorchBlock {
public static final BooleanProperty LIT = BlockStateProperties.LIT;
- private static final Map<BlockGetter, List<RedstoneTorchBlock.Toggle>> RECENT_TOGGLES = new WeakHashMap();
+ // Paper - Move the mapped list to World
public static final int RECENT_TOGGLE_TIMER = 60;
public static final int MAX_RECENT_TOGGLES = 8;
public static final int RESTART_DELAY = 160;
@@ -72,11 +72,15 @@ public class RedstoneTorchBlock extends TorchBlock {
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
boolean flag = this.hasNeighborSignal(world, pos, state);
- List list = (List) RedstoneTorchBlock.RECENT_TOGGLES.get(world);
-
- while (list != null && !list.isEmpty() && world.getGameTime() - ((RedstoneTorchBlock.Toggle) list.get(0)).when > 60L) {
- list.remove(0);
+ // Paper start
+ java.util.ArrayDeque<RedstoneTorchBlock.Toggle> redstoneUpdateInfos = world.redstoneUpdateInfos;
+ if (redstoneUpdateInfos != null) {
+ RedstoneTorchBlock.Toggle curr;
+ while ((curr = redstoneUpdateInfos.peek()) != null && world.getGameTime() - curr.when > 60L) {
+ redstoneUpdateInfos.poll();
+ }
}
+ // Paper end
// CraftBukkit start
org.bukkit.plugin.PluginManager manager = world.getCraftServer().getPluginManager();
@@ -152,9 +156,12 @@ public class RedstoneTorchBlock extends TorchBlock {
}
private static boolean isToggledTooFrequently(Level world, BlockPos pos, boolean addNew) {
- List<RedstoneTorchBlock.Toggle> list = (List) RedstoneTorchBlock.RECENT_TOGGLES.computeIfAbsent(world, (iblockaccess) -> {
- return Lists.newArrayList();
- });
+ // Paper start
+ java.util.ArrayDeque<RedstoneTorchBlock.Toggle> list = world.redstoneUpdateInfos;
+ if (list == null) {
+ list = world.redstoneUpdateInfos = new java.util.ArrayDeque<>();
+ }
+
if (addNew) {
list.add(new RedstoneTorchBlock.Toggle(pos.immutable(), world.getGameTime()));
@@ -162,9 +169,9 @@ public class RedstoneTorchBlock extends TorchBlock {
int i = 0;
- for (int j = 0; j < list.size(); ++j) {
- RedstoneTorchBlock.Toggle blockredstonetorch_redstoneupdateinfo = (RedstoneTorchBlock.Toggle) list.get(j);
-
+ for (java.util.Iterator<RedstoneTorchBlock.Toggle> iterator = list.iterator(); iterator.hasNext();) {
+ RedstoneTorchBlock.Toggle blockredstonetorch_redstoneupdateinfo = iterator.next();
+ // Paper end
if (blockredstonetorch_redstoneupdateinfo.pos.equals(pos)) {
++i;
if (i >= 8) {