even moaaar patches

This commit is contained in:
Jake Potrebic 2023-06-07 16:20:26 -07:00
parent c31a22c563
commit f0889559f3
No known key found for this signature in database
GPG key ID: ECE0B3C133C016C5
36 changed files with 132 additions and 131 deletions

View file

@ -0,0 +1,21 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ossi <oser0002@gmail.com>
Date: Fri, 12 Jun 2020 01:38:06 +0300
Subject: [PATCH] Fix CraftScheduler#runTaskTimerAsynchronously(Plugin,
Consumer<BukkitTask>, long, long) scheduling a non-repeating task instead of
a repeating one.
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
index ea7ebbc2674df727cf44856f172731ee083b8800..a423970cf7c927ea8a1bf842aaa236d3cf2d54c2 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -199,7 +199,7 @@ public class CraftScheduler implements BukkitScheduler {
@Override
public void runTaskTimerAsynchronously(Plugin plugin, Consumer<BukkitTask> task, long delay, long period) throws IllegalArgumentException {
- this.runTaskTimerAsynchronously(plugin, (Object) task, delay, CraftTask.NO_REPEATING);
+ this.runTaskTimerAsynchronously(plugin, (Object) task, delay, period);
}
@Override

View file

@ -0,0 +1,80 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Thu, 11 Jun 2020 17:29:42 -0700
Subject: [PATCH] Fix piston physics inconsistency - MC-188840
Pistons invoke physics when they move blocks. The physics can cause
tnt blocks to ignite. However, pistons (when storing the blocks they "moved")
don't actually go back to the world state sometimes to check if something
like that happened. As a result they end up moving the tnt like it was
never ignited. This resulted in the ability to create machines
that can duplicate tnt, called "world eaters".
This patch makes the piston logic retrieve the block state from the world
prevent this from occuring.
This patch also sets the moved pos to air immediately after creating
the moving piston TE. This prevents the block from being updated from
other physics calls by the piston.
Tested against the following tnt duper design:
https://www.youtube.com/watch?v=mS7xxNGhjxs
This patch also affects every type of machine that utilises
this mechanic. For example, dead coral is removed by a physics
update when being moved while it is attached to slimeblocks.
Standard piston machines that don't destroy or modify the
blocks they move by physics updates should be entirely
unaffected.
This patch fixes https://bugs.mojang.com/browse/MC-188840
This patch also fixes rail duping and carpet duping.
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index 4f6b7ed4809086811f0460544ba2ec0606f0f5da..9abae63e06c1dde9b8434d32bac8798808428d10 100644
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -412,14 +412,26 @@ public class PistonBaseBlock extends DirectionalBlock {
}
for (k = list.size() - 1; k >= 0; --k) {
- blockposition3 = (BlockPos) list.get(k);
- iblockdata1 = world.getBlockState(blockposition3);
+ // Paper start - fix a variety of piston desync dupes
+ boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication;
+ BlockPos oldPos = blockposition3 = (BlockPos) list.get(k);
+ iblockdata1 = allowDesync ? world.getBlockState(oldPos) : null;
+ // Paper end - fix a variety of piston desync dupes
blockposition3 = blockposition3.relative(enumdirection1);
map.remove(blockposition3);
BlockState iblockdata2 = (BlockState) Blocks.MOVING_PISTON.defaultBlockState().setValue(PistonBaseBlock.FACING, dir);
world.setBlock(blockposition3, iblockdata2, 68);
- world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, (BlockState) list1.get(k), dir, retract, false));
+ // Paper start - fix a variety of piston desync dupes
+ if (!allowDesync) {
+ iblockdata1 = world.getBlockState(oldPos);
+ map.replace(oldPos, iblockdata1);
+ }
+ world.setBlockEntity(MovingPistonBlock.newMovingBlockEntity(blockposition3, iblockdata2, allowDesync ? list1.get(k) : iblockdata1, dir, retract, false));
+ if (!allowDesync) {
+ world.setBlock(oldPos, Blocks.AIR.defaultBlockState(), 2 | 4 | 16 | 1024); // set air to prevent later physics updates from seeing this block
+ }
+ // Paper end - fix a variety of piston desync dupes
aiblockdata[j++] = iblockdata1;
}
diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
index 17a6327ab7b26dfab38881bbc0689b0b25f8f025..30fafbb26a347b73c72b9f5c30da3b01e42b851c 100644
--- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
@@ -288,7 +288,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
if (world.getBlockState(pos).is(Blocks.MOVING_PISTON)) {
BlockState blockState = Block.updateFromNeighbourShapes(blockEntity.movedState, world, pos);
if (blockState.isAir()) {
- world.setBlock(pos, blockEntity.movedState, 84);
+ world.setBlock(pos, blockEntity.movedState, io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication ? 84 : (84 | 2)); // Paper - force notify (flag 2), it's possible the set type by the piston block (which doesn't notify) set this block to air
Block.updateOrDestroy(blockEntity.movedState, blockState, world, pos, 3);
} else {
if (blockState.hasProperty(BlockStateProperties.WATERLOGGED) && blockState.getValue(BlockStateProperties.WATERLOGGED)) {

View file

@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Fri, 12 Jun 2020 13:33:19 -0700
Subject: [PATCH] Fix sand duping
If the falling block dies during teleportation (entity#move), then we need
to detect that by placing a check after the move.
diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
index 95bcd8f03a784287c5a6106c784448e54c4b531b..4a44109df0aece6661567dac5ebf6355de5d58c7 100644
--- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -129,6 +129,11 @@ public class FallingBlockEntity extends Entity {
@Override
public void tick() {
+ // Paper start - fix sand duping
+ if (this.isRemoved()) {
+ return;
+ }
+ // Paper end - fix sand duping
if (this.blockState.isAir()) {
this.discard();
} else {
@@ -140,6 +145,13 @@ public class FallingBlockEntity extends Entity {
}
this.move(MoverType.SELF, this.getDeltaMovement());
+
+ // Paper start - fix sand duping
+ if (this.isRemoved()) {
+ return;
+ }
+ // Paper end - fix sand duping
+
// Paper start - Configurable EntityFallingBlock height nerf
if (this.level().paperConfig().fixes.fallingBlockHeightNerf.test(v -> this.getY() > v)) {
if (this.dropItem && this.level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {

View file

@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: David Slovikosky <davidslovikosky@gmail.com>
Date: Tue, 9 Jun 2020 00:10:03 -0700
Subject: [PATCH] Fix missing chunks due to integer overflow
This patch fixes a bug in the EndIslandDensityFunction class where the distance
from 0,0 squared overflows the maximum size of an integer. The overflow leads
to hard chunk borders around 370,000 blocks from 0,0. After this cutoff there
is a few hundred thousand block gap before end land resuming to generate at
530,000 blocks from spawn. This is due to the integer flipping back and forth.
The fix for the issue is quite simple, casting chunk coordinates to longs
allows the distance calculation to avoid overflow and work as intended.
This issue is being tracked in Mojira ticket MC-159283
diff --git a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
index 299116c5c4d25c78a2af00bb44c4f51ac04286e8..fac92f37c32e0398ebc05d9a0378446fcabaef1a 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/DensityFunctions.java
@@ -502,7 +502,7 @@ public final class DensityFunctions {
int j = z / 2;
int k = x % 2;
int l = z % 2;
- float f = 100.0F - Mth.sqrt((float)(x * x + z * z)) * 8.0F;
+ float f = 100.0F - Mth.sqrt((long) x * (long) x + (long) z * (long) z) * 8.0F; // Paper - cast ints to long to avoid integer overflow
f = Mth.clamp(f, -100.0F, 80.0F);
for(int m = -12; m <= 12; ++m) {

View file

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Fri, 12 Jun 2020 16:51:39 -0700
Subject: [PATCH] Prevent position desync in playerconnection causing tp
exploit
Caused the server to revert to the player's overworld coordinates
after teleporting into the end.
Sidenote: The underlying issue is that the move call can teleport
entities and do other things like kill the entity. In the future,
to fix all exploits derieved from this usually unexpected
behaviour, we need to move all of this dangerous logic outside
of the move call and into an appropriate place in the tick method.
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index a9cdf3e774dbc8b689c7bbd95d94c8be32b33d92..76407e0d9081e848380c17b5f680a8560173edbc 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1434,6 +1434,11 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
+ // Paper start - prevent position desync
+ if (this.awaitingPositionFromClient != null) {
+ return; // ... thanks Mojang for letting move calls teleport across dimensions.
+ }
+ // Paper end - prevent position desync
double d11 = d7;
d6 = d0 - this.player.getX();

View file

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Phoenix616 <mail@moep.tv>
Date: Wed, 10 Jun 2020 23:55:15 +0100
Subject: [PATCH] Inventory getHolder method without block snapshot
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
index 8018ad8e5952c714f1bd445c91b4d5c846b9ba7a..015fc140db9162865f33cd6577cf758091a663c7 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java
@@ -540,6 +540,13 @@ public class CraftInventory implements Inventory {
return this.inventory.getOwner();
}
+ // Paper start - getHolder without snapshot
+ @Override
+ public InventoryHolder getHolder(boolean useSnapshot) {
+ return inventory instanceof net.minecraft.world.level.block.entity.BlockEntity ? ((net.minecraft.world.level.block.entity.BlockEntity) inventory).getOwner(useSnapshot) : getHolder();
+ }
+ // Paper end
+
@Override
public int getMaxStackSize() {
return this.inventory.getMaxStackSize();
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
index 01d425d359f2d6d87b6c01b435a9cfcfe11caa20..4707a651dc80086efa852bcfba38a534e7f1f3d0 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryDoubleChest.java
@@ -64,6 +64,13 @@ public class CraftInventoryDoubleChest extends CraftInventory implements DoubleC
return new DoubleChest(this);
}
+ // Paper start - getHolder without snapshot
+ @Override
+ public DoubleChest getHolder(boolean useSnapshot) {
+ return getHolder();
+ }
+ // Paper end
+
@Override
public Location getLocation() {
return this.getLeftSide().getLocation().add(this.getRightSide().getLocation()).multiply(0.5);

View file

@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nesaak <52047222+Nesaak@users.noreply.github.com>
Date: Sat, 23 May 2020 10:31:11 -0400
Subject: [PATCH] Improve Arrow API
Add method to get the arrow's itemstack and a method
to set the arrow's "noclip" status
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
index 376885c8148da619a3b203145d315ebaf44994fb..15abd085eeb0a31a925c1a8d6de903c9d4625a29 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArrow.java
@@ -102,6 +102,23 @@ public class CraftArrow extends AbstractProjectile implements AbstractArrow {
this.getHandle().pickup = net.minecraft.world.entity.projectile.AbstractArrow.Pickup.byOrdinal(status.ordinal());
}
+ // Paper start
+ @Override
+ public org.bukkit.craftbukkit.inventory.CraftItemStack getItemStack() {
+ return org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(getHandle().getPickupItem());
+ }
+
+ @Override
+ public void setNoPhysics(boolean noPhysics) {
+ this.getHandle().setNoPhysics(noPhysics);
+ }
+
+ @Override
+ public boolean hasNoPhysics() {
+ return this.getHandle().isNoPhysics();
+ }
+ // Paper end
+
@Override
public void setTicksLived(int value) {
super.setTicksLived(value);

View file

@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JRoy <joshroy126@gmail.com>
Date: Fri, 5 Jun 2020 18:24:06 -0400
Subject: [PATCH] Add and implement PlayerRecipeBookClickEvent
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 76407e0d9081e848380c17b5f680a8560173edbc..4e90349313c7e8a94949c94127dee24780a631eb 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3107,9 +3107,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
if (!this.player.containerMenu.stillValid(this.player)) {
ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu);
} else {
- this.server.getRecipeManager().byKey(packet.getRecipe()).ifPresent((irecipe) -> {
- ((RecipeBookMenu) this.player.containerMenu).handlePlacement(packet.isShiftDown(), irecipe, this.player);
- });
+ // Paper start - fire event for clicking recipes in the recipe book
+ com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent event = new com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent(
+ player.getBukkitEntity(), org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(packet.getRecipe()), packet.isShiftDown());
+ if (event.callEvent() && this.player.containerMenu instanceof RecipeBookMenu<?> recipeBookMenu) { // check if inventory changed during event handling
+ this.server.getRecipeManager().byKey(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getRecipe())).ifPresent((irecipe) -> {
+ recipeBookMenu.handlePlacement(event.isMakeAll(), irecipe, this.player);
+ });
+ }
+ // Paper end
}
}
}

View file

@ -0,0 +1,23 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Fri, 26 Jun 2020 22:35:08 -0700
Subject: [PATCH] Hide sync chunk writes behind flag
Syncing writes on each write call has terrible performance
on harddrives.
-DPaper.enable-sync-chunk-writes=true to enable
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
index d144fc518442762e45f213550a9b0a21f77fcdd1..818289e831e3dad29345c43265e2efd7689bc500 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
@@ -144,7 +144,7 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
this.maxWorldSize = this.get("max-world-size", (integer) -> {
return Mth.clamp(integer, 1, 29999984);
}, 29999984);
- this.syncChunkWrites = this.get("sync-chunk-writes", true);
+ this.syncChunkWrites = this.get("sync-chunk-writes", true) && Boolean.getBoolean("Paper.enable-sync-chunk-writes"); // Paper - hide behind flag
this.enableJmxMonitoring = this.get("enable-jmx-monitoring", false);
this.enableStatus = this.get("enable-status", true);
this.hideOnlinePlayers = this.get("hide-online-players", false);

View file

@ -0,0 +1,79 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mariell Hoversholm <proximyst@proximyst.com>
Date: Sat, 16 May 2020 10:05:30 +0200
Subject: [PATCH] Add permission for command blocks
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index 562534d15f6f70ff286be90fb512b807e00ad807..c185083abf2b4527a7fe046d83c64cd2cc5b5bb9 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -402,7 +402,7 @@ public class ServerPlayerGameMode {
BlockEntity tileentity = this.level.getBlockEntity(pos);
Block block = iblockdata.getBlock();
- if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) {
+ if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks() && !(block instanceof net.minecraft.world.level.block.CommandBlock && (this.player.isCreative() && this.player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission
this.level.sendBlockUpdated(pos, iblockdata, iblockdata, 3);
return false;
} else if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) {
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 4e90349313c7e8a94949c94127dee24780a631eb..792cc9567e1982f0cea75078045d70bc806934a4 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -871,7 +871,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
if (!this.server.isCommandBlockEnabled()) {
this.player.sendSystemMessage(Component.translatable("advMode.notEnabled"));
- } else if (!this.player.canUseGameMasterBlocks()) {
+ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission
this.player.sendSystemMessage(Component.translatable("advMode.notAllowed"));
} else {
BaseCommandBlock commandblocklistenerabstract = null;
@@ -938,7 +938,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
if (!this.server.isCommandBlockEnabled()) {
this.player.sendSystemMessage(Component.translatable("advMode.notEnabled"));
- } else if (!this.player.canUseGameMasterBlocks()) {
+ } else if (!this.player.canUseGameMasterBlocks() && (!this.player.isCreative() || !this.player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission
this.player.sendSystemMessage(Component.translatable("advMode.notAllowed"));
} else {
BaseCommandBlock commandblocklistenerabstract = packet.getCommandBlock(this.player.level());
diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
index 7f1efe0d9bc059a86166e8e3c5ef4ad23217f6a7..c138678fe82e6c1dd7ce634f90bcbfcad6159276 100644
--- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java
@@ -198,7 +198,7 @@ public abstract class BaseCommandBlock implements CommandSource {
}
public InteractionResult usedBy(Player player) {
- if (!player.canUseGameMasterBlocks()) {
+ if (!player.canUseGameMasterBlocks() && (!player.isCreative() || !player.getBukkitEntity().hasPermission("minecraft.commandblock"))) { // Paper - command block permission
return InteractionResult.PASS;
} else {
if (player.getCommandSenderWorld().isClientSide) {
diff --git a/src/main/java/net/minecraft/world/level/block/CommandBlock.java b/src/main/java/net/minecraft/world/level/block/CommandBlock.java
index 061a56e3828767cd6576d5a9edde5f3498e609d0..2e7c03b00bc941b86df6a7f1b2b188c9f0aede22 100644
--- a/src/main/java/net/minecraft/world/level/block/CommandBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/CommandBlock.java
@@ -130,7 +130,7 @@ public class CommandBlock extends BaseEntityBlock implements GameMasterBlock {
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
BlockEntity tileentity = world.getBlockEntity(pos);
- if (tileentity instanceof CommandBlockEntity && player.canUseGameMasterBlocks()) {
+ if (tileentity instanceof CommandBlockEntity && (player.canUseGameMasterBlocks() || (player.isCreative() && player.getBukkitEntity().hasPermission("minecraft.commandblock")))) { // Paper - command block permission
player.openCommandBlock((CommandBlockEntity) tileentity);
return InteractionResult.sidedSuccess(world.isClientSide);
} else {
diff --git a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
index 70d3949616c63038ad3e9bd1069db5ea2fb3f3b8..8e06bc11fb28baee3407bbfe9d7b3689d6f85ff2 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java
@@ -16,6 +16,7 @@ public final class CraftDefaultPermissions {
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".nbt.copy", "Gives the user the ability to copy NBT in creative", org.bukkit.permissions.PermissionDefault.TRUE, parent);
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick", "Gives the user the ability to use the debug stick in creative", org.bukkit.permissions.PermissionDefault.OP, parent);
DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".debugstick.always", "Gives the user the ability to use the debug stick in all game modes", org.bukkit.permissions.PermissionDefault.FALSE/* , parent */); // Paper - should not have this parent, as it's not a "vanilla" utility
+ DefaultPermissions.registerPermission(CraftDefaultPermissions.ROOT + ".commandblock", "Gives the user the ability to use command blocks.", org.bukkit.permissions.PermissionDefault.OP, parent); // Paper
// Spigot end
parent.recalculatePermissibles();
}

View file

@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 10 May 2020 22:12:46 -0400
Subject: [PATCH] Ensure Entity AABB's are never invalid
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index e17237a1fe56bf04516b0ee0489c781a225b6a81..316597f54e6ce8da0869e6398b048c618b4a1a7b 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -636,8 +636,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
public void setPos(double x, double y, double z) {
- this.setPosRaw(x, y, z);
- this.setBoundingBox(this.makeBoundingBox());
+ this.setPosRaw(x, y, z, true); // Paper - force bounding box update
+ // this.setBoundingBox(this.makeBoundingBox()); // Paper - move into setPositionRaw
}
protected AABB makeBoundingBox() {
@@ -4112,6 +4112,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
public final void setPosRaw(double x, double y, double z) {
+ // Paper start
+ this.setPosRaw(x, y, z, false);
+ }
+ public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
+ // Paper end
if (this.position.x != x || this.position.y != y || this.position.z != z) {
this.position = new Vec3(x, y, z);
int i = Mth.floor(x);
@@ -4129,6 +4134,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
this.levelCallback.onMove();
}
+ // Paper start - never allow AABB to become desynced from position
+ // hanging has its own special logic
+ if (!(this instanceof net.minecraft.world.entity.decoration.HangingEntity) && (forceBoundingBoxUpdate || this.position.x != x || this.position.y != y || this.position.z != z)) {
+ this.setBoundingBox(this.makeBoundingBox());
+ }
+ // Paper end
}
public void checkDespawn() {}

View file

@ -0,0 +1,131 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 28 Jun 2020 03:59:10 -0400
Subject: [PATCH] Fix Per World Difficulty / Remembering Difficulty
Fixes per world difficulty with /difficulty command and also
makes it so that the server keeps the last difficulty used instead
of restoring the server.properties every single load.
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 49283b13a88402ac5b54fd8c64e90a82499d09d7..afa54e9cdb81f08cd9703a3991b90dbd53861b61 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -800,7 +800,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (worldserver.getWorld().getKeepSpawnInMemory()) worldloadlistener.stop(); // Paper
// CraftBukkit start
// this.updateMobSpawningFlags();
- worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
+ worldserver.setSpawnSettings(worldserver.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals()); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean))
this.forceTicks = false;
// CraftBukkit end
@@ -1734,11 +1734,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
- public void setDifficulty(Difficulty difficulty, boolean forceUpdate) {
- if (forceUpdate || !this.worldData.isDifficultyLocked()) {
- this.worldData.setDifficulty(this.worldData.isHardcore() ? Difficulty.HARD : difficulty);
- this.updateMobSpawningFlags();
- this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate);
+ // Paper start - remember per level difficulty
+ public void setDifficulty(ServerLevel level, Difficulty difficulty, boolean forceUpdate) {
+ PrimaryLevelData worldData = level.serverLevelData;
+ if (forceUpdate || !worldData.isDifficultyLocked()) {
+ worldData.setDifficulty(worldData.isHardcore() ? Difficulty.HARD : difficulty);
+ level.setSpawnSettings(worldData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals());
+ // this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate);
+ // Paper end
}
}
@@ -1752,7 +1755,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
- worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
+ worldserver.setSpawnSettings(worldserver.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && ((DedicatedServer) this).settings.getProperties().spawnMonsters, this.isSpawningAnimals()); // Paper - per level difficulty (from setDifficulty(ServerLevel, Difficulty, boolean))
}
}
diff --git a/src/main/java/net/minecraft/server/commands/DifficultyCommand.java b/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
index 89be3991ef4fb2deb7276c5409cb571a7fb1f821..9c272f7cf8cbd2bbe147e57f7fabe135b6ff5c0b 100644
--- a/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
+++ b/src/main/java/net/minecraft/server/commands/DifficultyCommand.java
@@ -49,7 +49,7 @@ public class DifficultyCommand {
if (worldServer.getDifficulty() == difficulty) { // CraftBukkit
throw DifficultyCommand.ERROR_ALREADY_DIFFICULT.create(difficulty.getKey());
} else {
- worldServer.serverLevelData.setDifficulty(difficulty); // CraftBukkit
+ minecraftserver.setDifficulty(worldServer, difficulty, true); // Paper - don't skip other difficulty-changing logic (fix upstream's fix)
source.sendSuccess(() -> {
return Component.translatable("commands.difficulty.success", difficulty.getDisplayName());
}, true);
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 9d2eb13130d3b68fd0ca07243a3a41735f89c7b2..97b8c8cf85527db734e70679b29d64cdfbbddec3 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -326,7 +326,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@Override
public void forceDifficulty() {
- this.setDifficulty(this.getProperties().difficulty, true);
+ // this.setDifficulty(this.getProperties().difficulty, true); // Paper - Don't overwrite level.dat's difficulty, keep current
}
@Override
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 4495edee3b29c441d14460be1bb3f5e0ef4b9851..af06ca58e3ae488d23566b3db333067c62145ae0 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1161,7 +1161,7 @@ public class ServerPlayer extends Player {
this.isChangingDimension = true; // CraftBukkit - Set teleport invulnerability only if player changing worlds
this.connection.send(new ClientboundRespawnPacket(worldserver.dimensionTypeId(), worldserver.dimension(), BiomeManager.obfuscateSeed(worldserver.getSeed()), this.gameMode.getGameModeForPlayer(), this.gameMode.getPreviousGameModeForPlayer(), worldserver.isDebug(), worldserver.isFlat(), (byte) 3, this.getLastDeathLocation(), this.getPortalCooldown()));
- this.connection.send(new ClientboundChangeDifficultyPacket(this.level().getDifficulty(), this.level().getLevelData().isDifficultyLocked()));
+ this.connection.send(new ClientboundChangeDifficultyPacket(worldserver.getDifficulty(), this.level().getLevelData().isDifficultyLocked())); // Paper - fix difficulty sync issue
PlayerList playerlist = this.server.getPlayerList();
playerlist.sendPlayerPermissionLevel(this);
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 792cc9567e1982f0cea75078045d70bc806934a4..2768e46562f36bcb11cead95e65deb8db4884a12 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3345,7 +3345,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
public void handleChangeDifficulty(ServerboundChangeDifficultyPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
if (this.player.hasPermissions(2) || this.isSingleplayerOwner()) {
- this.server.setDifficulty(packet.getDifficulty(), false);
+ // this.server.setDifficulty(packet.getDifficulty(), false); // Paper - don't allow clients to change this
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index cd04bdf3637584b6ea7298b5d833d4a71ce427ff..ae1c8ec8b1cbfd5fab89d6cf5e33e2f209f82d03 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -964,8 +964,8 @@ public final class CraftServer implements Server {
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
this.console.paperConfigurations.reloadConfigs(this.console);
for (ServerLevel world : this.console.getAllLevels()) {
- world.serverLevelData.setDifficulty(config.difficulty);
- world.setSpawnSettings(config.spawnMonsters, config.spawnAnimals);
+ // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
+ world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters, config.spawnAnimals); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
for (SpawnCategory spawnCategory : SpawnCategory.values()) {
if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 76054a4fc036b1f9577aa8da215388c5137f3611..7cca27a4bedbb4b1f5cf0707e72052b6e155acfd 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1150,7 +1150,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public void setDifficulty(Difficulty difficulty) {
- this.getHandle().serverLevelData.setDifficulty(net.minecraft.world.Difficulty.byId(difficulty.getValue()));
+ this.getHandle().getServer().setDifficulty(this.getHandle(), net.minecraft.world.Difficulty.byId(difficulty.getValue()), true); // Paper - don't skip other difficulty-changing logic
}
@Override

View file

@ -0,0 +1,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 28 Jun 2020 19:27:20 -0400
Subject: [PATCH] Paper dumpitem command
Let's you quickly view the item in your hands NBT data
diff --git a/src/main/java/io/papermc/paper/command/PaperCommand.java b/src/main/java/io/papermc/paper/command/PaperCommand.java
index 1188d221be8a4f1dece514e3f66b99f60b556488..65209c7d15fc1b51e20c4f18cd44d1f61c769d09 100644
--- a/src/main/java/io/papermc/paper/command/PaperCommand.java
+++ b/src/main/java/io/papermc/paper/command/PaperCommand.java
@@ -41,6 +41,7 @@ public final class PaperCommand extends Command {
commands.put(Set.of("dumpplugins"), new DumpPluginsCommand());
commands.put(Set.of("fixlight"), new FixLightCommand());
commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand());
+ commands.put(Set.of("dumpitem"), new DumpItemCommand());
return commands.entrySet().stream()
.flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue())))
diff --git a/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f0b0fe73a47e6a5ca8706f11e78b4b08e6ccd9a
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/subcommands/DumpItemCommand.java
@@ -0,0 +1,59 @@
+package io.papermc.paper.command.subcommands;
+
+import io.papermc.paper.adventure.PaperAdventure;
+import io.papermc.paper.command.PaperSubcommand;
+import java.util.Objects;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.event.ClickEvent;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.world.item.ItemStack;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.entity.Player;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+import static net.kyori.adventure.text.Component.text;
+import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
+import static net.kyori.adventure.text.format.NamedTextColor.YELLOW;
+import static net.kyori.adventure.text.format.TextDecoration.ITALIC;
+
+@DefaultQualifier(NonNull.class)
+public final class DumpItemCommand implements PaperSubcommand {
+ @Override
+ public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
+ this.doDumpItem(sender);
+ return true;
+ }
+
+ private void doDumpItem(final CommandSender sender) {
+ if (!(sender instanceof Player)) {
+ sender.sendMessage("Only players can use this command");
+ return;
+ }
+ final ItemStack itemStack = CraftItemStack.asNMSCopy(((CraftPlayer) sender).getItemInHand());
+ final @Nullable CompoundTag tag = itemStack.getTag();
+ final @Nullable Component nbtComponent = tag == null ? null : PaperAdventure.asAdventure(net.minecraft.nbt.NbtUtils.toPrettyComponent(tag));
+ final String itemId = Objects.requireNonNull(((CraftWorld) ((CraftPlayer) sender).getWorld()).getHandle().registryAccess()
+ .registryOrThrow(Registries.ITEM).getKey(itemStack.getItem())).toString();
+ final Component message = text()
+ .append(text(itemId, YELLOW))
+ .apply(b -> {
+ if (nbtComponent != null) {
+ b.append(nbtComponent);
+ }
+ })
+ .build();
+ Bukkit.getConsoleSender().sendMessage(message);
+ sender.sendMessage(message);
+ sender.sendMessage(text().content(" Click to copy item to clipboard")
+ .color(GRAY)
+ .decorate(ITALIC)
+ .clickEvent(ClickEvent.copyToClipboard(tag == null ? itemId : (itemId + tag))));
+ }
+}

View file

@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 28 Jun 2020 19:08:41 -0400
Subject: [PATCH] Improve Legacy Component serialization size
Don't constantly send format: false for all formatting options when parent already
has it false
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
index 4fede2161792ba3e7cdf0cc5a1f533188becc6f7..0f70be614f8f5350ad558d0ae645cdf0027e1e76 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftChatMessage.java
@@ -47,6 +47,7 @@ public final class CraftChatMessage {
// Separate pattern with no group 3, new lines are part of previous string
private static final Pattern INCREMENTAL_PATTERN_KEEP_NEWLINES = Pattern.compile("(" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + "[0-9a-fk-orx])|((?:(?:https?):\\/\\/)?(?:[-\\w_\\.]{2,}\\.[a-z]{2,4}.*?(?=[\\.\\?!,;:]?(?:[" + String.valueOf(org.bukkit.ChatColor.COLOR_CHAR) + " ]|$))))", Pattern.CASE_INSENSITIVE);
// ChatColor.b does not explicitly reset, its more of empty
+ private static final Style EMPTY = Style.EMPTY.withItalic(false); // Paper - OBFHELPER
private static final Style RESET = Style.EMPTY.withBold(false).withItalic(false).withUnderlined(false).withStrikethrough(false).withObfuscated(false);
private final List<Component> list = new ArrayList<Component>();
@@ -68,6 +69,7 @@ public final class CraftChatMessage {
Matcher matcher = (keepNewlines ? StringMessage.INCREMENTAL_PATTERN_KEEP_NEWLINES : StringMessage.INCREMENTAL_PATTERN).matcher(message);
String match = null;
boolean needsAdd = false;
+ boolean hasReset = false; // Paper
while (matcher.find()) {
int groupId = 0;
while ((match = matcher.group(++groupId)) == null) {
@@ -113,7 +115,26 @@ public final class CraftChatMessage {
throw new AssertionError("Unexpected message format");
}
} else { // Color resets formatting
- this.modifier = StringMessage.RESET.withColor(format);
+ // Paper start - improve legacy formatting
+ Style previous = modifier;
+ modifier = (!hasReset ? RESET : EMPTY).withColor(format);
+ hasReset = true;
+ if (previous.isBold()) {
+ modifier = modifier.withBold(false);
+ }
+ if (previous.isItalic()) {
+ modifier = modifier.withItalic(false);
+ }
+ if (previous.isObfuscated()) {
+ modifier = modifier.withObfuscated(false);
+ }
+ if (previous.isStrikethrough()) {
+ modifier = modifier.withStrikethrough(false);
+ }
+ if (previous.isUnderlined()) {
+ modifier = modifier.withUnderlined(false);
+ }
+ // Paper end
}
needsAdd = true;
break;

View file

@ -0,0 +1,213 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 4 Jun 2020 02:24:49 -0400
Subject: [PATCH] Optimize Bit Operations by inlining
Inline bit operations and reduce instruction count to make these hot
operations faster
diff --git a/src/main/java/net/minecraft/core/BlockPos.java b/src/main/java/net/minecraft/core/BlockPos.java
index fbdbf61f49bd6867eea609d5572fb31ece094944..441ea6b9fd55a5288f264472d7297728d0546d6b 100644
--- a/src/main/java/net/minecraft/core/BlockPos.java
+++ b/src/main/java/net/minecraft/core/BlockPos.java
@@ -37,15 +37,16 @@ public class BlockPos extends Vec3i {
}).stable();
private static final Logger LOGGER = LogUtils.getLogger();
public static final BlockPos ZERO = new BlockPos(0, 0, 0);
- private static final int PACKED_X_LENGTH = 1 + Mth.log2(Mth.smallestEncompassingPowerOfTwo(30000000));
- private static final int PACKED_Z_LENGTH = PACKED_X_LENGTH;
- public static final int PACKED_Y_LENGTH = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
- private static final long PACKED_X_MASK = (1L << PACKED_X_LENGTH) - 1L;
- private static final long PACKED_Y_MASK = (1L << PACKED_Y_LENGTH) - 1L;
- private static final long PACKED_Z_MASK = (1L << PACKED_Z_LENGTH) - 1L;
- private static final int Y_OFFSET = 0;
- private static final int Z_OFFSET = PACKED_Y_LENGTH;
- private static final int X_OFFSET = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
+ // Paper start - static constants
+ private static final int PACKED_X_LENGTH = 26;
+ private static final int PACKED_Z_LENGTH = 26;
+ public static final int PACKED_Y_LENGTH = 12;
+ private static final long PACKED_X_MASK = 67108863;
+ private static final long PACKED_Y_MASK = 4095;
+ private static final long PACKED_Z_MASK = 67108863;
+ private static final int Z_OFFSET = 12;
+ private static final int X_OFFSET = 38;
+ // Paper end
public BlockPos(int x, int y, int z) {
super(x, y, z);
@@ -55,28 +56,29 @@ public class BlockPos extends Vec3i {
this(pos.getX(), pos.getY(), pos.getZ());
}
+ public static long getAdjacent(int baseX, int baseY, int baseZ, Direction enumdirection) { return asLong(baseX + enumdirection.getStepX(), baseY + enumdirection.getStepY(), baseZ + enumdirection.getStepZ()); } // Paper
public static long offset(long value, Direction direction) {
return offset(value, direction.getStepX(), direction.getStepY(), direction.getStepZ());
}
public static long offset(long value, int x, int y, int z) {
- return asLong(getX(value) + x, getY(value) + y, getZ(value) + z);
+ return asLong((int) (value >> 38) + x, (int) ((value << 52) >> 52) + y, (int) ((value << 26) >> 38) + z); // Paper - simplify/inline
}
public static int getX(long packedPos) {
- return (int)(packedPos << 64 - X_OFFSET - PACKED_X_LENGTH >> 64 - PACKED_X_LENGTH);
+ return (int) (packedPos >> 38); // Paper - simplify/inline
}
public static int getY(long packedPos) {
- return (int)(packedPos << 64 - PACKED_Y_LENGTH >> 64 - PACKED_Y_LENGTH);
+ return (int) ((packedPos << 52) >> 52); // Paper - simplify/inline
}
public static int getZ(long packedPos) {
- return (int)(packedPos << 64 - Z_OFFSET - PACKED_Z_LENGTH >> 64 - PACKED_Z_LENGTH);
+ return (int) ((packedPos << 26) >> 38); // Paper - simplify/inline
}
public static BlockPos of(long packedPos) {
- return new BlockPos(getX(packedPos), getY(packedPos), getZ(packedPos));
+ return new BlockPos((int) (packedPos >> 38), (int) ((packedPos << 52) >> 52), (int) ((packedPos << 26) >> 38)); // Paper - simplify/inline
}
public static BlockPos containing(double x, double y, double z) {
@@ -92,10 +94,7 @@ public class BlockPos extends Vec3i {
}
public static long asLong(int x, int y, int z) {
- long l = 0L;
- l |= ((long)x & PACKED_X_MASK) << X_OFFSET;
- l |= ((long)y & PACKED_Y_MASK) << 0;
- return l | ((long)z & PACKED_Z_MASK) << Z_OFFSET;
+ return (((long) x & (long) 67108863) << 38) | (((long) y & (long) 4095)) | (((long) z & (long) 67108863) << 12); // Paper - inline constants and simplify
}
public static long getFlatIndex(long y) {
diff --git a/src/main/java/net/minecraft/core/SectionPos.java b/src/main/java/net/minecraft/core/SectionPos.java
index eb97928380384b8c33cf142dd9a5db65951c94c6..392c3681c08d9e3d99cbabaf72d22c1d1518998d 100644
--- a/src/main/java/net/minecraft/core/SectionPos.java
+++ b/src/main/java/net/minecraft/core/SectionPos.java
@@ -38,7 +38,7 @@ public class SectionPos extends Vec3i {
}
public static SectionPos of(BlockPos pos) {
- return new SectionPos(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
+ return new SectionPos(pos.getX() >> 4, pos.getY() >> 4, pos.getZ() >> 4); // Paper
}
public static SectionPos of(ChunkPos chunkPos, int y) {
@@ -54,7 +54,7 @@ public class SectionPos extends Vec3i {
}
public static SectionPos of(long packed) {
- return new SectionPos(x(packed), y(packed), z(packed));
+ return new SectionPos((int) (packed >> 42), (int) (packed << 44 >> 44), (int) (packed << 22 >> 42)); // Paper
}
public static SectionPos bottomOf(ChunkAccess chunk) {
@@ -65,8 +65,16 @@ public class SectionPos extends Vec3i {
return offset(packed, direction.getStepX(), direction.getStepY(), direction.getStepZ());
}
+ // Paper start
+ public static long getAdjacentFromBlockPos(int x, int y, int z, Direction enumdirection) {
+ return (((long) ((x >> 4) + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y >> 4) + enumdirection.getStepY()) & 1048575L)) | (((long) ((z >> 4) + enumdirection.getStepZ()) & 4194303L) << 20);
+ }
+ public static long getAdjacentFromSectionPos(int x, int y, int z, Direction enumdirection) {
+ return (((long) (x + enumdirection.getStepX()) & 4194303L) << 42) | (((long) ((y) + enumdirection.getStepY()) & 1048575L)) | (((long) (z + enumdirection.getStepZ()) & 4194303L) << 20);
+ }
+ // Paper end
public static long offset(long packed, int x, int y, int z) {
- return asLong(x(packed) + x, y(packed) + y, z(packed) + z);
+ return (((long) ((int) (packed >> 42) + x) & 4194303L) << 42) | (((long) ((int) (packed << 44 >> 44) + y) & 1048575L)) | (((long) ((int) (packed << 22 >> 42) + z) & 4194303L) << 20); // Simplify to reduce instruction count
}
public static int posToSectionCoord(double coord) {
@@ -86,10 +94,7 @@ public class SectionPos extends Vec3i {
}
public static short sectionRelativePos(BlockPos pos) {
- int i = sectionRelative(pos.getX());
- int j = sectionRelative(pos.getY());
- int k = sectionRelative(pos.getZ());
- return (short)(i << 8 | k << 4 | j << 0);
+ return (short) ((pos.getX() & 15) << 8 | (pos.getZ() & 15) << 4 | pos.getY() & 15); // Paper - simplify/inline
}
public static int sectionRelativeX(short packedLocalPos) {
@@ -152,16 +157,16 @@ public class SectionPos extends Vec3i {
return this.getZ();
}
- public int minBlockX() {
- return sectionToBlockCoord(this.x());
+ public final int minBlockX() { // Paper - make final
+ return this.getX() << 4; // Paper - inline
}
- public int minBlockY() {
- return sectionToBlockCoord(this.y());
+ public final int minBlockY() { // Paper - make final
+ return this.getY() << 4; // Paper - inline
}
- public int minBlockZ() {
- return sectionToBlockCoord(this.z());
+ public int minBlockZ() { // Paper - make final
+ return this.getZ() << 4; // Paper - inline
}
public int maxBlockX() {
@@ -177,7 +182,8 @@ public class SectionPos extends Vec3i {
}
public static long blockToSection(long blockPos) {
- return asLong(blockToSectionCoord(BlockPos.getX(blockPos)), blockToSectionCoord(BlockPos.getY(blockPos)), blockToSectionCoord(BlockPos.getZ(blockPos)));
+ // b(a(BlockPosition.b(i)), a(BlockPosition.c(i)), a(BlockPosition.d(i)));
+ return (((long) (int) (blockPos >> 42) & 4194303L) << 42) | (((long) (int) ((blockPos << 52) >> 56) & 1048575L)) | (((long) (int) ((blockPos << 26) >> 42) & 4194303L) << 20); // Simplify to reduce instruction count
}
public static long getZeroNode(int x, int z) {
@@ -205,15 +211,18 @@ public class SectionPos extends Vec3i {
return asLong(blockToSectionCoord(pos.getX()), blockToSectionCoord(pos.getY()), blockToSectionCoord(pos.getZ()));
}
+ // Paper start
+ public static long blockPosAsSectionLong(int i, int j, int k) {
+ return (((long) (i >> 4) & 4194303L) << 42) | (((long) (j >> 4) & 1048575L)) | (((long) (k >> 4) & 4194303L) << 20);
+ }
+ // Paper end
+
public static long asLong(int x, int y, int z) {
- long l = 0L;
- l |= ((long)x & 4194303L) << 42;
- l |= ((long)y & 1048575L) << 0;
- return l | ((long)z & 4194303L) << 20;
+ return (((long) x & 4194303L) << 42) | (((long) y & 1048575L)) | (((long) z & 4194303L) << 20); // Paper - Simplify to reduce instruction count
}
public long asLong() {
- return asLong(this.x(), this.y(), this.z());
+ return (((long) getX() & 4194303L) << 42) | (((long) getY() & 1048575L)) | (((long) getZ() & 4194303L) << 20); // Paper - Simplify to reduce instruction count
}
@Override
@@ -226,16 +235,11 @@ public class SectionPos extends Vec3i {
}
public static Stream<SectionPos> cube(SectionPos center, int radius) {
- int i = center.x();
- int j = center.y();
- int k = center.z();
- return betweenClosedStream(i - radius, j - radius, k - radius, i + radius, j + radius, k + radius);
+ return betweenClosedStream(center.getX() - radius, center.getY() - radius, center.getZ() - radius, center.getX() + radius, center.getY() + radius, center.getZ() + radius); // Paper - simplify/inline
}
public static Stream<SectionPos> aroundChunk(ChunkPos center, int radius, int minY, int maxY) {
- int i = center.x;
- int j = center.z;
- return betweenClosedStream(i - radius, minY, j - radius, i + radius, maxY - 1, j + radius);
+ return betweenClosedStream(center.x - radius, 0, center.z - radius, center.x + radius, 15, center.z + radius); // Paper - simplify/inline
}
public static Stream<SectionPos> betweenClosedStream(final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ) {

View file

@ -0,0 +1,126 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 9 Jun 2020 03:33:03 -0400
Subject: [PATCH] Add Plugin Tickets to API Chunk Methods
Like previous versions, plugins loading chunks kept them loaded until
they garbage collected to avoid constant spamming of chunk loads
This adds tickets to a few more places so that they can be unloaded.
Additionally, this drops their ticket level to BORDER so they wont be ticking
so they will just sit inactive instead.
Using .loadChunk to keep a chunk ticking was a horrible idea for upstream
when we have TWO methods that are able to do that already in the API.
Also reduce their collection count down to a maximum of 1 second. Barely
anyone knows what chunk-gc is in bukkit.yml as its less relevant now, and
since this wasn't spigot behavior, this is safe to mostly ignore (unless someone
wants it to collect even faster, they can restore that setting back to 1 instead of 20+)
Not adding it to .getType() though to keep behavior consistent with vanilla for performance reasons.
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index ae1c8ec8b1cbfd5fab89d6cf5e33e2f209f82d03..fcf6585a66a95c3414c2b4eb384b9321aa678c22 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -377,7 +377,7 @@ public final class CraftServer implements Server {
this.overrideSpawnLimits();
console.autosavePeriod = this.configuration.getInt("ticks-per.autosave");
this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose"));
- TicketType.PLUGIN.timeout = this.configuration.getInt("chunk-gc.period-in-ticks");
+ TicketType.PLUGIN.timeout = Math.min(20, this.configuration.getInt("chunk-gc.period-in-ticks")); // Paper - cap plugin loads to 1 second
this.minimumAPI = this.configuration.getString("settings.minimum-api");
this.loadIcon();
@@ -944,7 +944,7 @@ public final class CraftServer implements Server {
this.console.setMotd(config.motd);
this.overrideSpawnLimits();
this.warningState = WarningState.value(this.configuration.getString("settings.deprecated-verbose"));
- TicketType.PLUGIN.timeout = this.configuration.getInt("chunk-gc.period-in-ticks");
+ TicketType.PLUGIN.timeout = Math.min(20, configuration.getInt("chunk-gc.period-in-ticks")); // Paper - cap plugin loads to 1 second
this.minimumAPI = this.configuration.getString("settings.minimum-api");
this.printSaveWarning = false;
console.autosavePeriod = this.configuration.getInt("ticks-per.autosave");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 7cca27a4bedbb4b1f5cf0707e72052b6e155acfd..4ee07d866c23ffe3061ccf0d663e5d4235b9007e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -280,7 +280,13 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public Chunk getChunkAt(int x, int z) {
- net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) this.world.getChunk(x, z, ChunkStatus.FULL, true);
+ // Paper start - add ticket to hold chunk for a little while longer if plugin accesses it
+ net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkSource().getChunkAtIfLoadedImmediately(x, z);
+ if (chunk == null) {
+ this.addTicket(x, z);
+ chunk = this.world.getChunkSource().getChunk(x, z, true);
+ }
+ // Paper end
return new CraftChunk(chunk);
}
@@ -294,6 +300,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
return new CraftChunk(this.getHandle(), x, z);
}
+ // Paper start
+ private void addTicket(int x, int z) {
+ io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> this.world.getChunkSource().addRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE)); // Paper
+ }
+ // Paper end
+
@Override
public Chunk getChunkAt(Block block) {
Preconditions.checkArgument(block != null, "null block");
@@ -359,7 +371,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
public boolean unloadChunkRequest(int x, int z) {
org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
if (this.isChunkLoaded(x, z)) {
- this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE);
+ this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 0, Unit.INSTANCE); // Paper
}
return true;
@@ -437,9 +449,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
// Paper start - Optimize this method
ChunkPos chunkPos = new ChunkPos(x, z);
+ ChunkAccess immediate = world.getChunkSource().getChunkAtIfLoadedImmediately(x, z); // Paper
+ if (immediate != null) return true; // Paper
if (!generate) {
- ChunkAccess immediate = world.getChunkSource().getChunkAtImmediately(x, z);
+
+ //IChunkAccess immediate = world.getChunkProvider().getChunkAtImmediately(x, z); // Paper
if (immediate == null) {
immediate = world.getChunkSource().chunkMap.getUnloadingChunk(x, z);
}
@@ -447,7 +462,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
if (!(immediate instanceof ImposterProtoChunk) && !(immediate instanceof net.minecraft.world.level.chunk.LevelChunk)) {
return false; // not full status
}
- world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
+ world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 0, Unit.INSTANCE); // Paper
world.getChunk(x, z); // make sure we're at ticket level 32 or lower
return true;
}
@@ -473,7 +488,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
// we do this so we do not re-read the chunk data on disk
}
- world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 1, Unit.INSTANCE);
+ world.getChunkSource().addRegionTicket(TicketType.PLUGIN, chunkPos, 0, Unit.INSTANCE); // Paper
world.getChunkSource().getChunk(x, z, ChunkStatus.FULL, true);
return true;
// Paper end
@@ -2167,6 +2182,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad(this.getHandle(), x, z, gen, ChunkStatus.FULL, true, priority, (c) -> {
net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> {
net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk)c;
+ if (chunk != null) this.addTicket(x, z); // Paper
ret.complete(chunk == null ? null : new CraftChunk(chunk));
});
});

View file

@ -0,0 +1,164 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sun, 9 Jun 2019 03:53:22 +0100
Subject: [PATCH] incremental chunk and player saving
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index afa54e9cdb81f08cd9703a3991b90dbd53861b61..b5cc8a2c46b928796c47832ee7430f63f616bfd2 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -863,7 +863,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
try {
this.isSaving = true;
- this.getPlayerList().saveAll();
+ this.getPlayerList().saveAll(); // Diff on change
flag3 = this.saveAllChunks(suppressLogs, flush, force);
} finally {
this.isSaving = false;
@@ -1389,13 +1389,28 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.status = this.buildServerStatus();
}
- if (this.autosavePeriod > 0 && this.tickCount % this.autosavePeriod == 0) { // CraftBukkit
- MinecraftServer.LOGGER.debug("Autosave started");
- this.profiler.push("save");
- this.saveEverything(true, false, false);
- this.profiler.pop();
- MinecraftServer.LOGGER.debug("Autosave finished");
+ // Paper start - incremental chunk and player saving
+ int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate;
+ if (playerSaveInterval < 0) {
+ playerSaveInterval = autosavePeriod;
}
+ this.profiler.push("save");
+ final boolean fullSave = autosavePeriod > 0 && this.tickCount % autosavePeriod == 0;
+ try {
+ this.isSaving = true;
+ if (playerSaveInterval > 0) {
+ this.playerList.saveAll(playerSaveInterval);
+ }
+ for (ServerLevel level : this.getAllLevels()) {
+ if (level.paperConfig().chunks.autoSaveInterval.value() > 0) {
+ level.saveIncrementally(fullSave);
+ }
+ }
+ } finally {
+ this.isSaving = false;
+ }
+ this.profiler.pop();
+ // Paper end
io.papermc.paper.util.CachedLists.reset(); // Paper
// Paper start - move executeAll() into full server tick timing
try (co.aikar.timings.Timing ignored = MinecraftTimings.processTasksTimer.startTiming()) {
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 2cbb2a02da1e5de18613ee977dafc92af9b552e9..fc66799e2a60ac9f67373e227e5955e88df8a039 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -603,6 +603,15 @@ public class ServerChunkCache extends ChunkSource {
} // Paper - Timings
}
+ // Paper start - duplicate save, but call incremental
+ public void saveIncrementally() {
+ this.runDistanceManagerUpdates();
+ try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings
+ this.chunkMap.saveIncrementally();
+ } // Paper - Timings
+ }
+ // Paper end
+
@Override
public void close() throws IOException {
// CraftBukkit start
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 8cdb2bdd404f2f091493bb7a93f62f764a8e511b..1a904c0d832197b5f820b9dd417c6d38f7fcc311 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1051,6 +1051,37 @@ public class ServerLevel extends Level implements WorldGenLevel {
return !this.server.isUnderSpawnProtection(this, pos, player) && this.getWorldBorder().isWithinBounds(pos);
}
+ // Paper start - derived from below
+ public void saveIncrementally(boolean doFull) {
+ ServerChunkCache chunkproviderserver = this.getChunkSource();
+
+ if (doFull) {
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld()));
+ }
+
+ try (co.aikar.timings.Timing ignored = this.timings.worldSave.startTiming()) {
+ if (doFull) {
+ this.saveLevelData();
+ }
+
+ this.timings.worldSaveChunks.startTiming(); // Paper
+ if (!this.noSave()) chunkproviderserver.saveIncrementally();
+ this.timings.worldSaveChunks.stopTiming(); // Paper
+
+ // Copied from save()
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
+ if (doFull) { // Paper
+ ServerLevel worldserver1 = this;
+
+ this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
+ this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save());
+ this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
+ }
+ // CraftBukkit end
+ }
+ }
+ // Paper end
+
public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) {
ServerChunkCache chunkproviderserver = this.getChunkSource();
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index af06ca58e3ae488d23566b3db333067c62145ae0..ad33c444100243b45bd8ee8603b21b41109faa2e 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -189,6 +189,7 @@ import org.bukkit.inventory.MainHand;
public class ServerPlayer extends Player {
private static final Logger LOGGER = LogUtils.getLogger();
+ public long lastSave = MinecraftServer.currentTick; // Paper
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
public ServerGamePacketListenerImpl connection;
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 498516c98f396e601e67b9e47a62e89f709f98a5..bc2bf0fc3bd169caadba9a2e3faf2fa333a41f04 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -535,6 +535,7 @@ public abstract class PlayerList {
protected void save(ServerPlayer player) {
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
+ player.lastSave = MinecraftServer.currentTick; // Paper
this.playerIo.save(player);
ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
@@ -1125,10 +1126,22 @@ public abstract class PlayerList {
}
public void saveAll() {
+ // Paper start - incremental player saving
+ this.saveAll(-1);
+ }
+
+ public void saveAll(int interval) {
io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
MinecraftTimings.savePlayers.startTiming(); // Paper
+ int numSaved = 0;
+ long now = MinecraftServer.currentTick;
for (int i = 0; i < this.players.size(); ++i) {
- this.save(this.players.get(i));
+ ServerPlayer entityplayer = this.players.get(i);
+ if (interval == -1 || now - entityplayer.lastSave >= interval) {
+ this.save(entityplayer);
+ if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; }
+ }
+ // Paper end
}
MinecraftTimings.savePlayers.stopTiming(); // Paper
return null; }); // Paper - ensure main

View file

@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 29 Jun 2020 03:26:17 -0400
Subject: [PATCH] Support old UUID format for NBT
We have stored UUID in plenty of places that did not get DFU'd
So just look for old format and load it if it exists.
diff --git a/src/main/java/net/minecraft/nbt/CompoundTag.java b/src/main/java/net/minecraft/nbt/CompoundTag.java
index 1d13bc15c56faa69699fb3ad39210233d6b6934d..7e94ebe06fc62293e665d6db19e42d947e7eb30f 100644
--- a/src/main/java/net/minecraft/nbt/CompoundTag.java
+++ b/src/main/java/net/minecraft/nbt/CompoundTag.java
@@ -196,6 +196,12 @@ public class CompoundTag implements Tag {
}
public void putUUID(String key, UUID value) {
+ // Paper start - support old format
+ if (this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
+ this.tags.remove(key + "Most");
+ this.tags.remove(key + "Least");
+ }
+ // Paper end
this.tags.put(key, NbtUtils.createUUID(value));
}
@@ -204,10 +210,20 @@ public class CompoundTag implements Tag {
* You must use {@link #hasUUID(String)} before or else it <b>will</b> throw an NPE.
*/
public UUID getUUID(String key) {
+ // Paper start - support old format
+ if (!contains(key, 11) && this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
+ return new UUID(this.getLong(key + "Most"), this.getLong(key + "Least"));
+ }
+ // Paper end
return NbtUtils.loadUUID(this.get(key));
}
public boolean hasUUID(String key) {
+ // Paper start - support old format
+ if (this.contains(key + "Most", 99) && this.contains(key + "Least", 99)) {
+ return true;
+ }
+ // Paper end
Tag tag = this.get(key);
return tag != null && tag.getType() == IntArrayTag.TYPE && ((IntArrayTag)tag).getAsIntArray().length == 4;
}
diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java
index 1e7ba8d82269d2d375b2f2d3fc21ed922cce0942..7bc60901297d27d88efb401d02b4bc06d8b28874 100644
--- a/src/main/java/net/minecraft/nbt/NbtUtils.java
+++ b/src/main/java/net/minecraft/nbt/NbtUtils.java
@@ -76,6 +76,11 @@ public final class NbtUtils {
if (nbt.contains("Name", 8)) {
string = nbt.getString("Name");
}
+ // Paper start - support string UUID's
+ if (nbt.contains("Id", 8)) {
+ uUID = UUID.fromString(nbt.getString("Id"));
+ }
+ // Paper end
if (nbt.hasUUID("Id")) {
uUID = nbt.getUUID("Id");

View file

@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 1 Jul 2020 03:12:06 -0400
Subject: [PATCH] Clean up duplicated GameProfile Properties
We had a bug where we accidently cloned properties resulting in skulls
growing to large sizes and preventing login.
This now automatically cleans up the extra properties.
diff --git a/src/main/java/net/minecraft/nbt/NbtUtils.java b/src/main/java/net/minecraft/nbt/NbtUtils.java
index 7bc60901297d27d88efb401d02b4bc06d8b28874..6dac24354192bea79a4b9eb721543110826790b2 100644
--- a/src/main/java/net/minecraft/nbt/NbtUtils.java
+++ b/src/main/java/net/minecraft/nbt/NbtUtils.java
@@ -94,7 +94,8 @@ public final class NbtUtils {
for(String string2 : compoundTag.getAllKeys()) {
ListTag listTag = compoundTag.getList(string2, 10);
- for(int i = 0; i < listTag.size(); ++i) {
+ if (listTag.size() == 0) continue; // Paper - remove duplicate properties
+ for (int i = listTag.size() - 1; i < listTag.size(); ++i) { // Paper - remove duplicate properties
CompoundTag compoundTag2 = listTag.getCompound(i);
String string3 = compoundTag2.getString("Value");
if (compoundTag2.contains("Signature", 8)) {
diff --git a/src/main/java/net/minecraft/world/item/PlayerHeadItem.java b/src/main/java/net/minecraft/world/item/PlayerHeadItem.java
index 98465d012357b76103d73952527c43c317d0f1bd..4969353e3a02ad70d973ae8780d018710f2462a3 100644
--- a/src/main/java/net/minecraft/world/item/PlayerHeadItem.java
+++ b/src/main/java/net/minecraft/world/item/PlayerHeadItem.java
@@ -53,6 +53,18 @@ public class PlayerHeadItem extends StandingAndWallBlockItem {
});
// CraftBukkit start
} else {
+ // Paper start - clean up old duplicated properties
+ CompoundTag properties = nbt.getCompound("SkullOwner").getCompound("Properties");
+ for (String key : properties.getAllKeys()) {
+ net.minecraft.nbt.ListTag values = properties.getList(key, 10);
+ if (values.size() > 1) {
+ net.minecraft.nbt.Tag texture = values.get(values.size() - 1);
+ values = new net.minecraft.nbt.ListTag();
+ values.add(texture);
+ properties.put(key, values);
+ }
+ }
+ // Paper end
net.minecraft.nbt.ListTag textures = nbt.getCompound("SkullOwner").getCompound("Properties").getList("textures", 10); // Safe due to method contracts
for (int i = 0; i < textures.size(); i++) {
if (textures.get(i) instanceof CompoundTag && !((CompoundTag) textures.get(i)).contains("Signature", 8) && ((CompoundTag) textures.get(i)).getString("Value").trim().isEmpty()) {

View file

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 1 Jul 2020 04:50:22 -0400
Subject: [PATCH] Convert legacy attributes in Item Meta
diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
index fac4097be2ee3d0bffbc92fb217f98831e78d6b3..233e372ba5d785352c9ac12dac37395bac63315c 100644
--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeMap.java
@@ -12,6 +12,20 @@ import org.bukkit.craftbukkit.util.CraftNamespacedKey;
public class CraftAttributeMap implements Attributable {
private final AttributeMap handle;
+ // Paper start - convert legacy attributes
+ private static final com.google.common.collect.ImmutableMap<String, String> legacyNMS = com.google.common.collect.ImmutableMap.<String, String>builder().put("generic.maxHealth", "generic.max_health").put("Max Health", "generic.max_health").put("zombie.spawnReinforcements", "zombie.spawn_reinforcements").put("Spawn Reinforcements Chance", "zombie.spawn_reinforcements").put("horse.jumpStrength", "horse.jump_strength").put("Jump Strength", "horse.jump_strength").put("generic.followRange", "generic.follow_range").put("Follow Range", "generic.follow_range").put("generic.knockbackResistance", "generic.knockback_resistance").put("Knockback Resistance", "generic.knockback_resistance").put("generic.movementSpeed", "generic.movement_speed").put("Movement Speed", "generic.movement_speed").put("generic.flyingSpeed", "generic.flying_speed").put("Flying Speed", "generic.flying_speed").put("generic.attackDamage", "generic.attack_damage").put("generic.attackKnockback", "generic.attack_knockback").put("generic.attackSpeed", "generic.attack_speed").put("generic.armorToughness", "generic.armor_toughness").build();
+
+ public static String convertIfNeeded(String nms) {
+ if (nms == null) {
+ return null;
+ }
+ nms = legacyNMS.getOrDefault(nms, nms);
+ if (!nms.toLowerCase().equals(nms) || nms.indexOf(' ') != -1) {
+ return null;
+ }
+ return nms;
+ }
+ // Paper end
public CraftAttributeMap(AttributeMap handle) {
this.handle = handle;
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index ad749401f8b473b3c7c239fea3af772014a29357..67d5a3f758eac50111c75ff3cd432f875cbe4ced 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -483,7 +483,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
AttributeModifier attribMod = CraftAttributeInstance.convert(nmsModifier);
- String attributeName = entry.getString(ATTRIBUTES_IDENTIFIER.NBT);
+ String attributeName = CraftAttributeMap.convertIfNeeded(entry.getString(ATTRIBUTES_IDENTIFIER.NBT)); // Paper
if (attributeName == null || attributeName.isEmpty()) {
continue;
}

View file

@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JRoy <joshroy126@gmail.com>
Date: Mon, 29 Jun 2020 17:03:06 -0400
Subject: [PATCH] Remove some streams from structures
This showed up a lot in the spark profiler, should have a low-medium performance improvement.
diff --git a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
index bb8d8edb47621665872a5e8fc01512ba40c1b913..5d721dc196a6bde511f46dbdedb2e1d98553ac52 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java
@@ -36,9 +36,10 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
int j = pos.getMinBlockZ();
ObjectList<Beardifier.Rigid> objectList = new ObjectArrayList<>(10);
ObjectList<JigsawJunction> objectList2 = new ObjectArrayList<>(32);
- world.startsForStructure(pos, (structure) -> {
+ // Paper start - replace for each
+ for (net.minecraft.world.level.levelgen.structure.StructureStart start : world.startsForStructure(pos, (structure) -> {
return structure.terrainAdaptation() != TerrainAdjustment.NONE;
- }).forEach((start) -> {
+ })) { // Paper end
TerrainAdjustment terrainAdjustment = start.getStructure().terrainAdaptation();
for(StructurePiece structurePiece : start.getPieces()) {
@@ -51,9 +52,11 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
}
for(JigsawJunction jigsawJunction : poolElementStructurePiece.getJunctions()) {
- int i = jigsawJunction.getSourceX();
- int j = jigsawJunction.getSourceZ();
- if (i > i - 12 && j > j - 12 && i < i + 15 + 12 && j < j + 15 + 12) {
+ // Paper start - decompile fix
+ int i2 = jigsawJunction.getSourceX();
+ int j2 = jigsawJunction.getSourceZ();
+ if (i2 > i - 12 && j2 > j - 12 && i2 < i + 15 + 12 && j2 < j + 15 + 12) {
+ // Paper end
objectList2.add(jigsawJunction);
}
}
@@ -63,7 +66,7 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
}
}
- });
+ } // Paper
return new Beardifier(objectList.iterator(), objectList2.iterator());
}

View file

@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JRoy <joshroy126@gmail.com>
Date: Wed, 1 Jul 2020 18:01:49 -0400
Subject: [PATCH] Remove streams from classes related villager gossip
diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
index 76dffb2705e5207db96895f82f1c7c5638f817c6..097007c1c25ba55d9916fc820dd1d1149d81f6f4 100644
--- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
+++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java
@@ -61,8 +61,22 @@ public class GossipContainer {
});
}
+ // Paper start - Remove streams from reputation
+ private List<GossipContainer.GossipEntry> decompress() {
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+ for (Map.Entry<UUID, GossipContainer.EntityGossips> entry : this.gossips.entrySet()) {
+ for (GossipContainer.GossipEntry cur : entry.getValue().decompress(entry.getKey())) {
+ if (cur.weightedValue() != 0) {
+ list.add(cur);
+ }
+ }
+ }
+ return list;
+ }
+ // Paper end
+
private Collection<GossipContainer.GossipEntry> selectGossipsForTransfer(RandomSource random, int count) {
- List<GossipContainer.GossipEntry> list = this.unpack().toList();
+ List<GossipContainer.GossipEntry> list = this.decompress(); // Paper - Remove streams from reputation
if (list.isEmpty()) {
return Collections.emptyList();
} else {
@@ -156,7 +170,7 @@ public class GossipContainer {
}
public <T> T store(DynamicOps<T> ops) {
- return GossipContainer.GossipEntry.LIST_CODEC.encodeStart(ops, this.unpack().toList()).resultOrPartial((error) -> {
+ return GossipContainer.GossipEntry.LIST_CODEC.encodeStart(ops, this.decompress()).resultOrPartial((error) -> {
LOGGER.warn("Failed to serialize gossips: {}", (Object)error);
}).orElseGet(ops::emptyList);
}
@@ -184,11 +198,23 @@ public class GossipContainer {
final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
public int weightedValue(Predicate<GossipType> gossipTypeFilter) {
- return this.entries.object2IntEntrySet().stream().filter((entry) -> {
- return gossipTypeFilter.test(entry.getKey());
- }).mapToInt((entry) -> {
- return entry.getIntValue() * (entry.getKey()).weight;
- }).sum();
+ // Paper start - Remove streams from reputation
+ int weight = 0;
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
+ if (gossipTypeFilter.test(entry.getKey())) {
+ weight += entry.getIntValue() * entry.getKey().weight;
+ }
+ }
+ return weight;
+ }
+
+ public List<GossipContainer.GossipEntry> decompress(UUID uuid) {
+ List<GossipContainer.GossipEntry> list = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
+ list.add(new GossipContainer.GossipEntry(uuid, entry.getKey(), entry.getIntValue()));
+ }
+ return list;
+ // Paper end
}
public Stream<GossipContainer.GossipEntry> unpack(UUID target) {

View file

@ -0,0 +1,83 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MiniDigger <admin@benndorf.dev>
Date: Sat, 6 Jun 2020 18:13:42 +0200
Subject: [PATCH] Support components in ItemMeta
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index 67d5a3f758eac50111c75ff3cd432f875cbe4ced..ad202473abbe4b302b825d9dd9dd75402190e824 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -877,11 +877,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
return CraftChatMessage.fromJSONComponent(displayName);
}
+ // Paper start
+ @Override
+ public net.md_5.bungee.api.chat.BaseComponent[] getDisplayNameComponent() {
+ return displayName == null ? new net.md_5.bungee.api.chat.BaseComponent[0] : net.md_5.bungee.chat.ComponentSerializer.parse(displayName);
+ }
+ // Paper end
@Override
public final void setDisplayName(String name) {
this.displayName = CraftChatMessage.fromStringOrNullToJSON(name);
}
+ // Paper start
+ @Override
+ public void setDisplayNameComponent(net.md_5.bungee.api.chat.BaseComponent[] component) {
+ this.displayName = net.md_5.bungee.chat.ComponentSerializer.toString(component);
+ }
+ // Paper end
@Override
public boolean hasDisplayName() {
return this.displayName != null;
@@ -1024,6 +1036,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
return this.lore == null ? null : new ArrayList<String>(Lists.transform(this.lore, CraftChatMessage::fromJSONComponent));
}
+ // Paper start
+ @Override
+ public List<net.md_5.bungee.api.chat.BaseComponent[]> getLoreComponents() {
+ return this.lore == null ? null : new ArrayList<>(this.lore.stream().map(entry ->
+ net.md_5.bungee.chat.ComponentSerializer.parse(entry)
+ ).collect(java.util.stream.Collectors.toList()));
+ }
+ // Paper end
@Override
public void setLore(List<String> lore) {
if (lore == null || lore.isEmpty()) {
@@ -1038,6 +1058,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
}
+ // Paper start
+ @Override
+ public void setLoreComponents(List<net.md_5.bungee.api.chat.BaseComponent[]> lore) {
+ if (lore == null) {
+ this.lore = null;
+ } else {
+ if (this.lore == null) {
+ safelyAdd(lore, this.lore = new ArrayList<>(lore.size()), false);
+ } else {
+ this.lore.clear();
+ safelyAdd(lore, this.lore, false);
+ }
+ }
+ }
+ // Paper end
@Override
public boolean hasCustomModelData() {
return this.customModelData != null;
@@ -1505,6 +1540,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
for (Object object : addFrom) {
+ // Paper start - support components
+ if(object instanceof net.md_5.bungee.api.chat.BaseComponent[]) {
+ addTo.add(net.md_5.bungee.chat.ComponentSerializer.toString((net.md_5.bungee.api.chat.BaseComponent[]) object));
+ } else
+ // Paper end
if (!(object instanceof String)) {
if (object != null) {
throw new IllegalArgumentException(addFrom + " cannot contain non-string " + object.getClass().getName());

View file

@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 9 Dec 2022 03:10:23 -0800
Subject: [PATCH] Improve/fix EntityTargetLivingEntityEvent
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
index 5aeef564cdaabeed88a52635e56073cca3a9d1f1..2fd7763f125421cf6bb3c0faf26253c9034183fc 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/StopAttackingIfTargetInvalid.java
@@ -47,17 +47,30 @@ public class StopAttackingIfTargetInvalid {
if (entityinsentient.canAttack(entityliving) && (!shouldForgetIfTargetUnreachable || !StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) && entityliving.isAlive() && entityliving.level() == entityinsentient.level() && !alternativeCondition.test(entityliving)) {
return true;
} else {
+ // Paper start - better track target change reason
+ final EntityTargetEvent.TargetReason reason;
+ if (!entityinsentient.canAttack(entityliving)) {
+ reason = EntityTargetEvent.TargetReason.TARGET_INVALID;
+ } else if (shouldForgetIfTargetUnreachable && StopAttackingIfTargetInvalid.isTiredOfTryingToReachTarget(entityinsentient, behaviorbuilder_b.tryGet(memoryaccessor1))) {
+ reason = EntityTargetEvent.TargetReason.FORGOT_TARGET;
+ } else if (!entityliving.isAlive()) {
+ reason = EntityTargetEvent.TargetReason.TARGET_DIED;
+ } else if (entityliving.level != entityinsentient.level) {
+ reason = EntityTargetEvent.TargetReason.TARGET_OTHER_LEVEL;
+ } else {
+ reason = EntityTargetEvent.TargetReason.TARGET_INVALID;
+ }
+ // Paper end
// CraftBukkit start
- LivingEntity old = entityinsentient.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null);
- EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, null, (old != null && !old.isAlive()) ? EntityTargetEvent.TargetReason.TARGET_DIED : EntityTargetEvent.TargetReason.FORGOT_TARGET);
+ EntityTargetEvent event = CraftEventFactory.callEntityTargetLivingEvent(entityinsentient, null, reason); // Paper
if (event.isCancelled()) {
return false;
}
- if (event.getTarget() == null) {
- memoryaccessor.erase();
- return true;
- }
- entityliving = ((CraftLivingEntity) event.getTarget()).getHandle();
+ // if (event.getTarget() == null) { // Paper - this is wrong, you are skipping the forgetCallback
+ // memoryaccessor.erase();
+ // return true;
+ // }
+ // entityliving = ((CraftLivingEntity) event.getTarget()).getHandle();
// CraftBukkit end
forgetCallback.accept(entityinsentient, entityliving);
memoryaccessor.erase();

View file

@ -0,0 +1,54 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Thu, 2 Jul 2020 18:11:43 -0500
Subject: [PATCH] Add entity liquid API
== AT ==
public net.minecraft.world.entity.Entity isInRain()Z
public net.minecraft.world.entity.Entity isInBubbleColumn()Z
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 5d8532bc2c4253aa3941ff8c4d48cc8c3860b3b0..5d01b33df41ecc51e2c2b44bad34a65e823d69ce 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1308,5 +1308,40 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason getEntitySpawnReason() {
return getHandle().spawnReason;
}
+
+ @Override
+ public boolean isUnderWater() {
+ return getHandle().isUnderWater();
+ }
+
+ @Override
+ public boolean isInRain() {
+ return getHandle().isInRain();
+ }
+
+ @Override
+ public boolean isInBubbleColumn() {
+ return getHandle().isInBubbleColumn();
+ }
+
+ @Override
+ public boolean isInWaterOrRain() {
+ return getHandle().isInWaterOrRain();
+ }
+
+ @Override
+ public boolean isInWaterOrBubbleColumn() {
+ return getHandle().isInWaterOrBubble();
+ }
+
+ @Override
+ public boolean isInWaterOrRainOrBubbleColumn() {
+ return getHandle().isInWaterRainOrBubble();
+ }
+
+ @Override
+ public boolean isInLava() {
+ return getHandle().isInLava();
+ }
// Paper end
}

View file

@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Wed, 1 Jul 2020 11:57:40 -0500
Subject: [PATCH] Update itemstack legacy name and lore
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 441fbeb3226b698648788de5ad58b94a66499a41..020737fba27b6615905da4ac1724bbac8ec0bf4f 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -171,6 +171,44 @@ public final class ItemStack {
list.sort((java.util.Comparator<? super net.minecraft.nbt.Tag>) enchantSorter); // Paper
} catch (Exception ignored) {}
}
+
+ private void processText() {
+ CompoundTag display = getTagElement("display");
+ if (display != null) {
+ if (display.contains("Name", 8)) {
+ String json = display.getString("Name");
+ if (json != null && json.contains("\u00A7")) {
+ try {
+ display.put("Name", convert(json));
+ } catch (com.google.gson.JsonParseException jsonparseexception) {
+ display.remove("Name");
+ }
+ }
+ }
+ if (display.contains("Lore", 9)) {
+ ListTag list = display.getList("Lore", 8);
+ for (int index = 0; index < list.size(); index++) {
+ String json = list.getString(index);
+ if (json != null && json.contains("\u00A7")) { // Only try if it has legacy in the unparsed json
+ try {
+ list.set(index, convert(json));
+ } catch (com.google.gson.JsonParseException e) {
+ list.set(index, net.minecraft.nbt.StringTag.valueOf(org.bukkit.craftbukkit.util.CraftChatMessage.toJSON(net.minecraft.network.chat.Component.literal(""))));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private net.minecraft.nbt.StringTag convert(String json) {
+ Component component = Component.Serializer.fromJson(json);
+ if (component.getContents() instanceof net.minecraft.network.chat.contents.LiteralContents literalContents && literalContents.text().contains("\u00A7") && component.getSiblings().isEmpty()) {
+ // Only convert if the root component is a single comp with legacy in it, don't convert already normal components
+ component = org.bukkit.craftbukkit.util.CraftChatMessage.fromString(literalContents.text())[0];
+ }
+ return net.minecraft.nbt.StringTag.valueOf(org.bukkit.craftbukkit.util.CraftChatMessage.toJSON(component));
+ }
// Paper end
public ItemStack(ItemLike item) {
@@ -222,6 +260,7 @@ public final class ItemStack {
this.tag = nbttagcompound.getCompound("tag").copy();
// CraftBukkit end
this.processEnchantOrder(this.tag); // Paper
+ this.processText(); // Paper
this.getItem().verifyTagAfterLoad(this.tag);
}

View file

@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Wyatt Childers <wchilders@nearce.com>
Date: Fri, 3 Jul 2020 14:57:05 -0400
Subject: [PATCH] Spawn player in correct world on login
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index bc2bf0fc3bd169caadba9a2e3faf2fa333a41f04..2d75a19def131b63e238dd81bb651834ed53df6b 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -212,7 +212,18 @@ public abstract class PlayerList {
}
// CraftBukkit end
- if (nbttagcompound != null) {
+ // Paper start - move logic in Entity to here, to use bukkit supplied world UUID.
+ if (nbttagcompound != null && nbttagcompound.contains("WorldUUIDMost") && nbttagcompound.contains("WorldUUIDLeast")) {
+ UUID uid = new UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast"));
+ org.bukkit.World bWorld = org.bukkit.Bukkit.getServer().getWorld(uid);
+ if (bWorld != null) {
+ resourcekey = ((CraftWorld) bWorld).getHandle().dimension();
+ } else {
+ resourcekey = Level.OVERWORLD;
+ }
+ } else if (nbttagcompound != null) {
+ // Vanilla migration support
+ // Paper end
DataResult<ResourceKey<Level>> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbttagcompound.get("Dimension"))); // CraftBukkit - decompile error
Logger logger = PlayerList.LOGGER;

View file

@ -0,0 +1,165 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Fri, 3 Jul 2020 11:58:56 -0500
Subject: [PATCH] Add PrepareResultEvent
Adds a new event for all crafting stations that generate a result slot item
Anvil, Grindstone and Smithing now extend this event
diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
index d15f01f5a4f14d25ded9de015c70cbc7977a6a77..e0c3a4ba27e21c3692e601acd0af60873bcbb84c 100644
--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
@@ -338,6 +338,7 @@ public class AnvilMenu extends ItemCombinerMenu {
}
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
return true;
} else {
return false;
diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
index fe1ce65b35e83ee0ada77e44b080729346bb3c2d..819187dbcf468d9278ce33bd97688476aab53f8e 100644
--- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
@@ -150,6 +150,7 @@ public class CartographyTableMenu extends AbstractContainerMenu {
this.setupResultSlot(itemstack, itemstack1, itemstack2);
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
}
private void setupResultSlot(ItemStack map, ItemStack item, ItemStack oldResult) {
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
index 2c263447aa8853f18d1c1d476b49a47f6e9ca2ad..03d3edadf39d4871a332808458870ea9479669c4 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -159,6 +159,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
super.slotsChanged(inventory);
if (inventory == this.repairSlots) {
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
index 4087e381b2250be387b608d8742f6a6009a52879..ff770b9ce68a62418de0c7ed389650626fa1dcb2 100644
--- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
@@ -110,6 +110,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu {
super.slotsChanged(inventory);
if (inventory == this.inputSlots) {
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, this instanceof SmithingMenu ? 3 : 2); // Paper
}
}
diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java
index edc8da447a531cec3a0590ee39811f0949ca7dda..c4766df6d64b484375e5e3474e97dee196c0fef4 100644
--- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java
@@ -248,7 +248,8 @@ public class LoomMenu extends AbstractContainerMenu {
this.resultSlot.set(ItemStack.EMPTY);
}
- this.broadcastChanges();
+ // this.broadcastChanges(); // Paper - done below
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 3); // Paper
} else {
this.resultSlot.set(ItemStack.EMPTY);
this.selectablePatterns = List.of();
diff --git a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java
index a56061fe2a12254827209b17fb0b9d89032649ba..dbfd36859010a1f950769708fbc5fc604c0754a9 100644
--- a/src/main/java/net/minecraft/world/inventory/SmithingMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/SmithingMenu.java
@@ -114,6 +114,7 @@ public class SmithingMenu extends ItemCombinerMenu {
}
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
}
@Override
diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
index 8734a129244271b370f965fcbf488a14ce04684a..00f01ab2eff69c18b50ec07b7623af66c66a28b6 100644
--- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
@@ -180,6 +180,7 @@ public class StonecutterMenu extends AbstractContainerMenu {
this.setupRecipeList(inventory, itemstack);
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
}
private void setupRecipeList(Container input, ItemStack stack) {
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 7af0710c40c1453bd0bd8ecb4ea7606bbe76c20f..2502da6e68f97a7c37f1756d6845e531da1663c3 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1624,26 +1624,53 @@ public class CraftEventFactory {
return event;
}
- public static PrepareAnvilEvent callPrepareAnvilEvent(InventoryView view, ItemStack item) {
- PrepareAnvilEvent event = new PrepareAnvilEvent(view, CraftItemStack.asCraftMirror(item).clone());
- event.getView().getPlayer().getServer().getPluginManager().callEvent(event);
+ // Paper start - disable this method, handled below
+ public static void callPrepareAnvilEvent(InventoryView view, ItemStack item) { // Paper - verify nothing uses return - handled below in PrepareResult
+ PrepareAnvilEvent event = new PrepareAnvilEvent(view, CraftItemStack.asCraftMirror(item)); // Paper - remove clone
+ //event.getView().getPlayer().getServer().getPluginManager().callEvent(event); // Paper - disable event
event.getInventory().setItem(2, event.getResult());
- return event;
+ //return event; // Paper
}
+ // Paper end
- public static PrepareGrindstoneEvent callPrepareGrindstoneEvent(InventoryView view, ItemStack item) {
- PrepareGrindstoneEvent event = new PrepareGrindstoneEvent(view, CraftItemStack.asCraftMirror(item).clone());
- event.getView().getPlayer().getServer().getPluginManager().callEvent(event);
+ // Paper start - disable this method, handled below
+ public static void callPrepareGrindstoneEvent(InventoryView view, ItemStack item) {
+ PrepareGrindstoneEvent event = new PrepareGrindstoneEvent(view, CraftItemStack.asCraftMirror(item)); // Paper - remove clone
+ // event.getView().getPlayer().getServer().getPluginManager().callEvent(event); // Paper - disable event
event.getInventory().setItem(2, event.getResult());
- return event;
+ // return event; // Paper
}
+ // Paper end
- public static PrepareSmithingEvent callPrepareSmithingEvent(InventoryView view, ItemStack item) {
- PrepareSmithingEvent event = new PrepareSmithingEvent(view, CraftItemStack.asCraftMirror(item).clone());
- event.getView().getPlayer().getServer().getPluginManager().callEvent(event);
+ // Paper start - disable this method, handled in callPrepareResultEvent
+ public static void callPrepareSmithingEvent(InventoryView view, ItemStack item) { // Paper - verify nothing uses return - handled below in PrepareResult
+ PrepareSmithingEvent event = new PrepareSmithingEvent(view, CraftItemStack.asCraftMirror(item)); // Paper - remove clone
+ //event.getView().getPlayer().getServer().getPluginManager().callEvent(event); // Paper - disable event
event.getInventory().setResult(event.getResult());
- return event;
+ //return event; // Paper
}
+ // Paper end
+
+ // Paper start - support specific overrides for prepare result
+ public static void callPrepareResultEvent(AbstractContainerMenu container, int resultSlot) {
+ com.destroystokyo.paper.event.inventory.PrepareResultEvent event;
+ InventoryView view = container.getBukkitView();
+ org.bukkit.inventory.ItemStack origItem = view.getTopInventory().getItem(resultSlot);
+ CraftItemStack result = origItem != null ? CraftItemStack.asCraftCopy(origItem) : null;
+ if (view.getTopInventory() instanceof org.bukkit.inventory.AnvilInventory) {
+ event = new PrepareAnvilEvent(view, result);
+ } else if (view.getTopInventory() instanceof org.bukkit.inventory.GrindstoneInventory) {
+ event = new PrepareGrindstoneEvent(view, result);
+ } else if (view.getTopInventory() instanceof org.bukkit.inventory.SmithingInventory) {
+ event = new PrepareSmithingEvent(view, result);
+ } else {
+ event = new com.destroystokyo.paper.event.inventory.PrepareResultEvent(view, result);
+ }
+ event.callEvent();
+ event.getInventory().setItem(resultSlot, event.getResult());
+ container.broadcastChanges();;
+ }
+ // Paper end
/**
* Mob spawner event.

View file

@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 5 Jul 2020 14:59:31 -0400
Subject: [PATCH] Don't check chunk for portal on world gen entity add
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index d9ee22bbd654a2f39c443262b4a11f997ed1559e..84f56d1eb0075f1f3d3d52d1b893732c3804c276 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3484,7 +3484,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
Entity entity = this.getVehicle();
super.stopRiding(suppressCancellation); // Paper - suppress
- if (entity != null && entity != this.getVehicle() && !this.level().isClientSide) {
+ if (entity != null && entity != this.getVehicle() && !this.level().isClientSide && entity.valid) { // Paper - don't process on world gen
this.dismountVehicle(entity);
}

View file

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrew Steinborn <git@steinborn.me>
Date: Sun, 5 Jul 2020 22:38:18 -0400
Subject: [PATCH] Optimize NetworkManager Exception Handling
diff --git a/src/main/java/net/minecraft/network/ConnectionProtocol.java b/src/main/java/net/minecraft/network/ConnectionProtocol.java
index a30fa3d54b70ab63d24dd67a69f39742335aff1e..a79da4bc0ed06ff8ede0a34f00194f927251099b 100644
--- a/src/main/java/net/minecraft/network/ConnectionProtocol.java
+++ b/src/main/java/net/minecraft/network/ConnectionProtocol.java
@@ -329,6 +329,7 @@ public enum ConnectionProtocol implements BundlerInfo.Provider {
@Nullable
public Packet<?> createPacket(int id, FriendlyByteBuf buf) {
+ if (id < 0 || id >= this.idToDeserializer.size()) return null; // Paper
Function<FriendlyByteBuf, ? extends Packet<T>> function = this.idToDeserializer.get(id);
return function != null ? function.apply(buf) : null;
}
diff --git a/src/main/java/net/minecraft/network/Varint21FrameDecoder.java b/src/main/java/net/minecraft/network/Varint21FrameDecoder.java
index 99b581052f937b0f2d6b5d73de699008c1d51774..81ec2011a93bb94200ad750f4666ba1cd8be11c5 100644
--- a/src/main/java/net/minecraft/network/Varint21FrameDecoder.java
+++ b/src/main/java/net/minecraft/network/Varint21FrameDecoder.java
@@ -8,9 +8,20 @@ import io.netty.handler.codec.CorruptedFrameException;
import java.util.List;
public class Varint21FrameDecoder extends ByteToMessageDecoder {
+ private final byte[] lenBuf = new byte[3]; // Paper
+ @Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) {
+ // Paper start - if channel is not active just discard the packet
+ if (!channelHandlerContext.channel().isActive()) {
+ byteBuf.skipBytes(byteBuf.readableBytes());
+ return;
+ }
+ // Paper end
byteBuf.markReaderIndex();
- byte[] bs = new byte[3];
+ // Paper start - reuse temporary length buffer
+ byte[] bs = lenBuf;
+ java.util.Arrays.fill(bs, (byte) 0);
+ // Paper end
for(int i = 0; i < bs.length; ++i) {
if (!byteBuf.isReadable()) {

View file

@ -0,0 +1,22 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Wed, 8 Jul 2020 11:24:30 -0500
Subject: [PATCH] Fix arrows never despawning MC-125757
This forces the despawn counter to start ticking regardless of
state after the arrow has been alive for 200 ticks (10 seconds)
instead of getting stuck in a never despawn state (bubble columns,
etc).
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 86a82ecdcffc27b523fddc2709bbd92f315e8590..a0d688128a1268fa1acf7c339cde15df5dce1c82 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java
@@ -200,6 +200,7 @@ public abstract class AbstractArrow extends Projectile {
++this.inGroundTime;
} else {
+ if (tickCount > 200) this.tickDespawn(); // Paper - tick despawnCounter regardless after 10 seconds
this.inGroundTime = 0;
Vec3 vec3d2 = this.position();

View file

@ -0,0 +1,53 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 11 Jul 2020 03:54:28 -0400
Subject: [PATCH] Thread Safe Vanilla Command permission checking
Datapacks check this on load and are built concurrently. This was breaking them badly due
to race conditions.
Plus, .canUse we want to be safe for async anyways.
diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
index 20a7cdf87f307878d66922aaac0c60cff218e46c..39844531b03eb8a6c70700b4ecbf0ff1a557424d 100644
--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java
+++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java
@@ -75,10 +75,10 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
public synchronized boolean canUse(final S source) {
if (source instanceof CommandSourceStack) {
try {
- ((CommandSourceStack) source).currentCommand = this;
+ ((CommandSourceStack) source).currentCommand.put(Thread.currentThread(), this); // Paper
return this.requirement.test(source);
} finally {
- ((CommandSourceStack) source).currentCommand = null;
+ ((CommandSourceStack) source).currentCommand.remove(Thread.currentThread()); // Paper
}
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
index 66bd75ee66840f17cc7d00ff89adcb88d83e4dc9..308b3a36f063c401a447f9b7f0364700eee5a54c 100644
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
@@ -64,7 +64,7 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy
private final CommandSigningContext signingContext;
private final TaskChainer chatMessageChainer;
private final IntConsumer returnValueConsumer;
- public volatile CommandNode currentCommand; // CraftBukkit
+ public java.util.Map<Thread, CommandNode> currentCommand = new java.util.concurrent.ConcurrentHashMap<>(); // CraftBukkit // Paper
public boolean bypassSelectorPermissions = false; // Paper
public CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity) {
@@ -203,9 +203,11 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy
@Override
public boolean hasPermission(int level) {
// CraftBukkit start
- CommandNode currentCommand = this.currentCommand;
+ // Paper start - fix concurrency issue
+ CommandNode currentCommand = this.currentCommand.get(Thread.currentThread());
if (currentCommand != null) {
return this.hasPermission(level, org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(currentCommand));
+ // Paper end
}
// CraftBukkit end

View file

@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: JRoy <joshroy126@gmail.com>
Date: Wed, 15 Jul 2020 21:42:52 -0400
Subject: [PATCH] Fix SPIGOT-5989
Before this fix, if a player was respawning to a respawn anchor and
the respawn location was modified away from the anchor with the
PlayerRespawnEvent, the anchor would still lose some charge.
This fixes that by checking if the modified spawn location is
still at a respawn anchor.
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 2d75a19def131b63e238dd81bb651834ed53df6b..20fe7dd46b8b641fe628695f17edac42fd000bb6 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -794,6 +794,7 @@ public abstract class PlayerList {
// Paper start
boolean isBedSpawn = false;
boolean isRespawn = false;
+ boolean isLocAltered = false; // Paper - Fix SPIGOT-5989
// Paper end
// CraftBukkit start - fire PlayerRespawnEvent
@@ -804,7 +805,7 @@ public abstract class PlayerList {
Optional optional;
if (blockposition != null) {
- optional = net.minecraft.world.entity.player.Player.findRespawnPositionAndUseSpawnBlock(worldserver1, blockposition, f, flag1, flag);
+ optional = net.minecraft.world.entity.player.Player.findRespawnPositionAndUseSpawnBlock(worldserver1, blockposition, f, flag1, true); // Paper - Fix SPIGOT-5989
} else {
optional = Optional.empty();
}
@@ -848,7 +849,12 @@ public abstract class PlayerList {
}
// Spigot End
- location = respawnEvent.getRespawnLocation();
+ // Paper start - Fix SPIGOT-5989
+ if (!location.equals(respawnEvent.getRespawnLocation()) ) {
+ location = respawnEvent.getRespawnLocation();
+ isLocAltered = true;
+ }
+ // Paper end
if (!flag) entityplayer.reset(); // SPIGOT-4785
isRespawn = true; // Paper
} else {
@@ -888,8 +894,14 @@ public abstract class PlayerList {
}
// entityplayer1.initInventoryMenu();
entityplayer1.setHealth(entityplayer1.getHealth());
- if (flag2) {
- entityplayer1.connection.send(new ClientboundSoundPacket(SoundEvents.RESPAWN_ANCHOR_DEPLETE, SoundSource.BLOCKS, (double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), 1.0F, 1.0F, worldserver1.getRandom().nextLong()));
+ // Paper start - Fix SPIGOT-5989
+ if (flag2 && !isLocAltered) {
+ if (!flag1) {
+ BlockState data = worldserver1.getBlockState(blockposition);
+ worldserver1.setBlock(blockposition, data.setValue(net.minecraft.world.level.block.RespawnAnchorBlock.CHARGE, data.getValue(net.minecraft.world.level.block.RespawnAnchorBlock.CHARGE) - 1), 3);
+ }
+ entityplayer1.connection.send(new ClientboundSoundPacket(SoundEvents.RESPAWN_ANCHOR_DEPLETE, SoundSource.BLOCKS, (double) location.getX(), (double) location.getY(), (double) location.getZ(), 1.0F, 1.0F, worldserver1.getRandom().nextLong()));
+ // Paper end
}
// Added from changeDimension
this.sendAllPlayerInfo(entityplayer); // Update health, etc...

View file

@ -0,0 +1,50 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Fri, 10 Jul 2020 13:12:33 -0500
Subject: [PATCH] Fix SPIGOT-5824 Bukkit world-container is not used
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 13797f0a55d62a022eda19f3134fe6256d15ff67..62bcf73e0ea23a610b67709457a8c6d0cdf3233b 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -169,8 +169,17 @@ public class Main {
return;
}
- File file = (File) optionset.valueOf("universe"); // CraftBukkit
- Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper
+ // Paper start - fix SPIGOT-5824
+ File file;
+ File userCacheFile = new File(Services.USERID_CACHE_FILE);
+ if (optionset.has("universe")) {
+ file = (File) optionset.valueOf("universe"); // CraftBukkit
+ userCacheFile = new File(file, Services.USERID_CACHE_FILE);
+ } else {
+ file = new File(bukkitConfiguration.getString("settings.world-container", "."));
+ }
+ // Paper end - fix SPIGOT-5824
+ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, userCacheFile, optionset); // Paper
// CraftBukkit start
String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName);
LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath());
diff --git a/src/main/java/net/minecraft/server/Services.java b/src/main/java/net/minecraft/server/Services.java
index f1cc27809c1e8612f7c4fa912f5e39c07b09d808..a9b2c8cd4dcd3f884e4306bebee9334d3848fce5 100644
--- a/src/main/java/net/minecraft/server/Services.java
+++ b/src/main/java/net/minecraft/server/Services.java
@@ -22,12 +22,12 @@ public record Services(MinecraftSessionService sessionService, ServicesKeySet se
return java.util.Objects.requireNonNull(this.paperConfigurations);
}
// Paper end
- private static final String USERID_CACHE_FILE = "usercache.json";
+ public static final String USERID_CACHE_FILE = "usercache.json"; // Paper - private -> public
- public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, joptsimple.OptionSet optionSet) throws Exception { // Paper
+ public static Services create(YggdrasilAuthenticationService authenticationService, File rootDirectory, File userCacheFile, joptsimple.OptionSet optionSet) throws Exception { // Paper
MinecraftSessionService minecraftSessionService = authenticationService.createMinecraftSessionService();
GameProfileRepository gameProfileRepository = authenticationService.createProfileRepository();
- GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, new File(rootDirectory, "usercache.json"));
+ GameProfileCache gameProfileCache = new GameProfileCache(gameProfileRepository, userCacheFile); // Paper
// Paper start
final java.nio.file.Path legacyConfigPath = ((File) optionSet.valueOf("paper-settings")).toPath();
final java.nio.file.Path configDirPath = ((File) optionSet.valueOf("paper-settings-directory")).toPath();

View file

@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
Date: Fri, 10 Jul 2020 12:38:12 -0500
Subject: [PATCH] Fix SPIGOT-5885 Unable to disable advancements
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 62bcf73e0ea23a610b67709457a8c6d0cdf3233b..b51636545036ee7492c9f907f94295b1dd66a811 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -169,6 +169,7 @@ public class Main {
return;
}
+ org.spigotmc.SpigotConfig.disabledAdvancements = spigotConfiguration.getStringList("advancements.disabled"); // Paper - fix SPIGOT-5885, must be set early in init
// Paper start - fix SPIGOT-5824
File file;
File userCacheFile = new File(Services.USERID_CACHE_FILE);

View file

@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 13 Jul 2020 06:22:54 -0700
Subject: [PATCH] Fix AdvancementDataPlayer leak due from quitting early in
login
Move the criterion storage to the AdvancementDataPlayer object
itself, so the criterion object stores no references - and thus
needs no cleanup.
diff --git a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
index 70d4467e8e4dd9be38a7bfe8494efb6e67e18b9a..4b0e967fac5adb54b2d26ee8f7a1ced259ad11db 100644
--- a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
+++ b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
@@ -14,22 +14,24 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.storage.loot.LootContext;
public abstract class SimpleCriterionTrigger<T extends AbstractCriterionTriggerInstance> implements CriterionTrigger<T> {
- private final Map<PlayerAdvancements, Set<CriterionTrigger.Listener<T>>> players = Maps.newIdentityHashMap();
+ //private final Map<PlayerAdvancements, Set<CriterionTrigger.Listener<T>>> players = Maps.newIdentityHashMap(); // Paper - moved into AdvancementDataPlayer to fix memory leak
+
+ public SimpleCriterionTrigger() {}
@Override
public final void addPlayerListener(PlayerAdvancements manager, CriterionTrigger.Listener<T> conditions) {
- this.players.computeIfAbsent(manager, (managerx) -> {
+ manager.criterionData.computeIfAbsent(this, (managerx) -> { // Paper - fix AdvancementDataPlayer leak
return Sets.newHashSet();
}).add(conditions);
}
@Override
public final void removePlayerListener(PlayerAdvancements manager, CriterionTrigger.Listener<T> conditions) {
- Set<CriterionTrigger.Listener<T>> set = this.players.get(manager);
+ Set<CriterionTrigger.Listener<T>> set = (Set) manager.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak
if (set != null) {
set.remove(conditions);
if (set.isEmpty()) {
- this.players.remove(manager);
+ manager.criterionData.remove(this); // Paper - fix AdvancementDataPlayer leak
}
}
@@ -37,7 +39,7 @@ public abstract class SimpleCriterionTrigger<T extends AbstractCriterionTriggerI
@Override
public final void removePlayerListeners(PlayerAdvancements tracker) {
- this.players.remove(tracker);
+ tracker.criterionData.remove(this); // Paper - fix AdvancementDataPlayer leak
}
protected abstract T createInstance(JsonObject obj, ContextAwarePredicate playerPredicate, DeserializationContext predicateDeserializer);
@@ -50,7 +52,7 @@ public abstract class SimpleCriterionTrigger<T extends AbstractCriterionTriggerI
protected void trigger(ServerPlayer player, Predicate<T> predicate) {
PlayerAdvancements playerAdvancements = player.getAdvancements();
- Set<CriterionTrigger.Listener<T>> set = this.players.get(playerAdvancements);
+ Set<CriterionTrigger.Listener<T>> set = (Set) playerAdvancements.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak
if (set != null && !set.isEmpty()) {
LootContext lootContext = EntityPredicate.createContext(player, player);
List<CriterionTrigger.Listener<T>> list = null;
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
index 100781852965e09c92aca34785673c5de51c7107..9034faaf7b169788abad01d3da9c65ad5ddc4b8b 100644
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
@@ -62,6 +62,7 @@ public class PlayerAdvancements {
@Nullable
private Advancement lastSelectedTab;
private boolean isFirstPacket = true;
+ public final Map<net.minecraft.advancements.critereon.SimpleCriterionTrigger, Set<CriterionTrigger.Listener>> criterionData = new java.util.IdentityHashMap<>(); // Paper - fix advancement data player leakage
public PlayerAdvancements(DataFixer dataFixer, PlayerList playerManager, ServerAdvancementManager advancementLoader, Path filePath, ServerPlayer owner) {
this.dataFixer = dataFixer;