some work

This commit is contained in:
Lulu13022002 2023-09-22 18:11:35 +02:00
parent ac7e4ad35e
commit 8baf510f92
No known key found for this signature in database
GPG key ID: 491C8F0B8ACDEB01
64 changed files with 158 additions and 180 deletions

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: SoSeDiK <mrsosedik@gmail.com>
Date: Tue, 11 Oct 2022 23:30:32 +0300
Subject: [PATCH] Expose pre-collision moving velocity to
VehicleBlockCollisionEvent
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index ca93f7a5484fb93cdfb6bb7749ffbaefb6f43042..d9f6b0e0b20f4106ffead6b773b5489b71924c61 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1156,7 +1156,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
if (!bl.getType().isAir()) {
- VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl);
+ VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl, org.bukkit.craftbukkit.util.CraftVector.toBukkit(moveVector)); // Paper - Expose pre-collision velocity
this.level.getCraftServer().getPluginManager().callEvent(event);
}
}

View file

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 15 Sep 2021 14:52:42 -0700
Subject: [PATCH] config for disabling entity tag tags
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
index c11e805dc4b77f08cadb0e99d86635036405da3e..9afc81ccb237c3655d64cdbe8a0db9a4d7791043 100644
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
@@ -492,6 +492,13 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
if (world.isClientSide || !entity.onlyOpCanSetNbt() || player != null && minecraftserver.getPlayerList().isOp(player.getGameProfile())) {
CompoundTag nbttagcompound1 = entity.saveWithoutId(new CompoundTag());
UUID uuid = entity.getUUID();
+ // Paper start - filter out protected tags
+ if (player == null || !player.getBukkitEntity().hasPermission("minecraft.nbt.place")) {
+ for (net.minecraft.commands.arguments.NbtPathArgument.NbtPath tag : world.paperConfig().entities.spawning.filteredEntityTagNbtPaths) {
+ tag.remove(itemNbt.getCompound("EntityTag"));
+ }
+ }
+ // Paper end
nbttagcompound1.merge(itemNbt.getCompound("EntityTag"));
entity.setUUID(uuid);

View file

@ -1,51 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 8 Jan 2023 17:38:28 -0800
Subject: [PATCH] Use single player info update packet on join
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 771341996a41723cceb945e18ac8b5adae337d91..5cb45e6e5f73996b2a603589b8571cf0155a42c5 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -3616,7 +3616,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
this.signedMessageDecoder = session.createMessageDecoder(this.player.getUUID());
this.chatMessageChain.append((executor) -> {
this.player.setChatSession(session);
- this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT), List.of(this.player)));
+ this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT), List.of(this.player)), this.player); // Paper
return CompletableFuture.completedFuture((Object) null);
});
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 490f2d6f7a43d0a5915a80960c1c7c48b3eea19f..8547e7ff2f1f5b7701fb0f3c3010c14601a5f83e 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -353,6 +353,7 @@ public abstract class PlayerList {
// CraftBukkit start - sendAll above replaced with this loop
ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player));
+ final List<ServerPlayer> onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - use single player info update packet
for (int i = 0; i < this.players.size(); ++i) {
ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i);
@@ -360,12 +361,17 @@ public abstract class PlayerList {
entityplayer1.connection.send(packet);
}
- if (!bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) {
+ if (entityplayer1 == player || !bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) { // Paper - don't include joining player
continue;
}
- player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1)));
+ onlinePlayers.add(entityplayer1); // Paper - use single player info update packet
}
+ // Paper start - use single player info update packet
+ if (!onlinePlayers.isEmpty()) {
+ player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers));
+ }
+ // Paper end
player.sentListPacket = true;
player.supressTrackerForLogin = false; // Paper
((ServerLevel)player.level()).getChunkSource().chunkMap.addEntity(player); // Paper - track entity now

View file

@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bjarne Koll <lynxplay101@gmail.com>
Date: Tue, 10 Jan 2023 21:06:42 +0100
Subject: [PATCH] Correctly shrink items during EntityResurrectEvent
The EntityResurrectEvent logic is supposed to locate a totem of undying
in any of the interaction slots of the player inventory and then, if the
called EntityResurrectEvent is not cancelled, shrink that item by 1,
usually reducing it to zero.
For this, the logic iterates over the items in the interaction slots and
breaks out the loop if a totem of undying was found.
However, even if no totem of undying was found, the iteration item stack
variable remains as a refernce to the last interaction slot probed.
Plugins uncancelling a EntityResurrectEvent, which is published
pre-cancelled to listeners if no totem of undying could be found,
would hence cause the server logic to shrink completely unrelated items
found in, at the writing of this patch, the players off hand slot.
This patch corrects this behaviour by only shrinking the item if a totem
of undying was found and the event was called uncancelled.
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 6a50f553753d4a7c596ad081c6bb3557afa884d6..634d272b71c464b9279a7e3ba83e9eacfcff580b 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1582,7 +1582,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
this.level().getCraftServer().getPluginManager().callEvent(event);
if (!event.isCancelled()) {
- if (!itemstack1.isEmpty()) {
+ if (!itemstack1.isEmpty() && itemstack != null) { // Paper - only reduce item if actual totem was found
itemstack1.shrink(1);
}
if (itemstack != null && this instanceof ServerPlayer) {

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lama06 <andreasprues36@gmail.com>
Date: Sat, 21 Jan 2023 13:53:23 +0100
Subject: [PATCH] Win Screen API
== AT ==
public net.minecraft.server.level.ServerPlayer seenCredits
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index e50651a0c9f856d0cfca3b8ee3b664f19393690f..241cc7dda1de8c711050b269b74b1b74adef5fce 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1213,6 +1213,25 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
this.getHandle().connection.send(packet);
}
+ // Paper start
+ @Override
+ public void showWinScreen() {
+ if (getHandle().connection == null) return;
+ var packet = new ClientboundGameEventPacket(ClientboundGameEventPacket.WIN_GAME, 1);
+ getHandle().connection.send(packet);
+ }
+
+ @Override
+ public boolean hasSeenWinScreen() {
+ return getHandle().seenCredits;
+ }
+
+ @Override
+ public void setHasSeenWinScreen(boolean hasSeenWinScreen) {
+ getHandle().seenCredits = hasSeenWinScreen;
+ }
+ // Paper end
+
@Override
public void setRotation(float yaw, float pitch) {
// Paper start - Teleport API

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Josh Roy <joshroy126@gmail.com>
Date: Mon, 23 Jan 2023 19:19:01 -0500
Subject: [PATCH] Remove CraftItemStack#setAmount null assignment
This creates a problem with Paper's item serialization
api where deserialized items, which are internally
created as a CraftItemStack, will be completely lost if
#setAmount(0) is invoked (since the underlying handle
is set to null), while a regular Bukkit ItemStack
simply sets the amount field to zero, retaining the
item's data.
Vanilla treats items with zero amounts the same as items
with less than zero amounts, so this code doesn't create
a problem with operations on the vanilla ItemStack.
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index 28e6933e5b02d1d2f983968692bffa2b9e572051..ce82f313007762b6d1d9f006f21a8858e2976efb 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -157,7 +157,7 @@ public final class CraftItemStack extends ItemStack {
}
this.handle.setCount(amount);
- if (amount == 0) {
+ if (false && amount == 0) { // Paper - remove CraftItemStack#setAmount null assignment
this.handle = null;
}
}

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 26 Jan 2023 16:19:26 -0800
Subject: [PATCH] Fix force-opening enchantment tables
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
index 6f694f68c2792da7088c2aba1d2b201f802b3a5c..50f2a94c5f2e9f7c08cea137d8d84d65e2c41326 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
@@ -402,7 +402,18 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
// If there isn't an enchant table we can force create one, won't be very useful though.
BlockPos pos = CraftLocation.toBlockPosition(location);
- this.getHandle().openMenu(((EnchantmentTableBlock) Blocks.ENCHANTING_TABLE).getMenuProvider(null, this.getHandle().level(), pos));
+ // Paper start
+ MenuProvider menuProvider = ((EnchantmentTableBlock) Blocks.ENCHANTING_TABLE).getMenuProvider(null, this.getHandle().level(), pos);
+ if (menuProvider == null) {
+ if (!force) {
+ return null;
+ }
+ menuProvider = new net.minecraft.world.SimpleMenuProvider((syncId, inventory, player) -> {
+ return new net.minecraft.world.inventory.EnchantmentMenu(syncId, inventory, net.minecraft.world.inventory.ContainerLevelAccess.create(this.getHandle().level(), pos));
+ }, Component.translatable("container.enchant"));
+ }
+ this.getHandle().openMenu(menuProvider);
+ // Paper end
if (force) {
this.getHandle().containerMenu.checkReachable = false;

View file

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: TheTuso <piotrekpasztor@gmail.com>
Date: Thu, 2 Feb 2023 16:40:41 +0100
Subject: [PATCH] Add Entity Body Yaw API
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 1186ee7cc4671892346b7173d10125febcfbf88a..4c2818f2ab2c53a836622d0ef17b19ecd1762908 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1430,6 +1430,31 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
public boolean isInPowderedSnow() {
return getHandle().isInPowderSnow || getHandle().wasInPowderSnow; // depending on the location in the entity "tick" either could be needed.
}
+
+ @Override
+ public double getX() {
+ return this.entity.getX();
+ }
+
+ @Override
+ public double getY() {
+ return this.entity.getY();
+ }
+
+ @Override
+ public double getZ() {
+ return this.entity.getZ();
+ }
+
+ @Override
+ public float getPitch() {
+ return this.entity.getXRot();
+ }
+
+ @Override
+ public float getYaw() {
+ return this.entity.getBukkitYaw();
+ }
// Paper end
// Paper Start - Collision API
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index 4b8d619e447d761cb09252388e09c843bbc7d3a2..ae1a86798a5d65ec6ee4388c650e09850c3f35f8 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -1056,6 +1056,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
this.damageItemStack0(this.getHandle().getItemBySlot(nmsSlot), amount, nmsSlot);
}
+ @Override
+ public float getBodyYaw() {
+ return this.getHandle().getVisualRotationYInDegrees();
+ }
+
+ @Override
+ public void setBodyYaw(float bodyYaw) {
+ this.getHandle().setYBodyRot(bodyYaw);
+ }
+
private void damageItemStack0(net.minecraft.world.item.ItemStack nmsStack, int amount, net.minecraft.world.entity.EquipmentSlot slot) {
nmsStack.hurtAndBreak(amount, this.getHandle(), livingEntity -> {
if (slot != null) {

View file

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Warrior <50800980+Warriorrrr@users.noreply.github.com>
Date: Mon, 27 Feb 2023 19:16:07 +0100
Subject: [PATCH] Fix MC-157464 Prevent sleeping villagers moving towards food
Fixes sleeping villagers moving to nearby food by adding an !isSleeping predicate
Relevant links:
https://bugs.mojang.com/browse/MC-157464
https://github.com/PaperMC/Paper/issues/8569
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
index 9400556aca4cd06ad311975d74a9e7eb2ccd9c73..cd7a90ec1073b2b452ca70decefe6a594445003b 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/VillagerGoalPackages.java
@@ -22,7 +22,7 @@ public class VillagerGoalPackages {
private static final float STROLL_SPEED_MODIFIER = 0.4F;
public static ImmutableList<Pair<Integer, ? extends BehaviorControl<? super Villager>>> getCorePackage(VillagerProfession profession, float speed) {
- return ImmutableList.of(Pair.of(0, new Swim(0.8F)), Pair.of(0, InteractWithDoor.create()), Pair.of(0, new LookAtTargetSink(45, 90)), Pair.of(0, new VillagerPanicTrigger()), Pair.of(0, WakeUp.create()), Pair.of(0, ReactToBell.create()), Pair.of(0, SetRaidStatus.create()), Pair.of(0, ValidateNearbyPoi.create(profession.heldJobSite(), MemoryModuleType.JOB_SITE)), Pair.of(0, ValidateNearbyPoi.create(profession.acquirableJobSite(), MemoryModuleType.POTENTIAL_JOB_SITE)), Pair.of(1, new MoveToTargetSink()), Pair.of(2, PoiCompetitorScan.create()), Pair.of(3, new LookAndFollowTradingPlayerSink(speed)), Pair.of(5, GoToWantedItem.create(speed, false, 4)), Pair.of(6, AcquirePoi.create(profession.acquirableJobSite(), MemoryModuleType.JOB_SITE, MemoryModuleType.POTENTIAL_JOB_SITE, true, Optional.empty())), Pair.of(7, new GoToPotentialJobSite(speed)), Pair.of(8, YieldJobSite.create(speed)), Pair.of(10, AcquirePoi.create((poiType) -> {
+ return ImmutableList.of(Pair.of(0, new Swim(0.8F)), Pair.of(0, InteractWithDoor.create()), Pair.of(0, new LookAtTargetSink(45, 90)), Pair.of(0, new VillagerPanicTrigger()), Pair.of(0, WakeUp.create()), Pair.of(0, ReactToBell.create()), Pair.of(0, SetRaidStatus.create()), Pair.of(0, ValidateNearbyPoi.create(profession.heldJobSite(), MemoryModuleType.JOB_SITE)), Pair.of(0, ValidateNearbyPoi.create(profession.acquirableJobSite(), MemoryModuleType.POTENTIAL_JOB_SITE)), Pair.of(1, new MoveToTargetSink()), Pair.of(2, PoiCompetitorScan.create()), Pair.of(3, new LookAndFollowTradingPlayerSink(speed)), Pair.of(5, GoToWantedItem.create(villager -> !villager.isSleeping(), speed, false, 4)), Pair.of(6, AcquirePoi.create(profession.acquirableJobSite(), MemoryModuleType.JOB_SITE, MemoryModuleType.POTENTIAL_JOB_SITE, true, Optional.empty())), Pair.of(7, new GoToPotentialJobSite(speed)), Pair.of(8, YieldJobSite.create(speed)), Pair.of(10, AcquirePoi.create((poiType) -> { // Paper - Fix MC-157464
return poiType.is(PoiTypes.HOME);
}, MemoryModuleType.HOME, false, Optional.of((byte)14))), Pair.of(10, AcquirePoi.create((poiType) -> {
return poiType.is(PoiTypes.MEETING);

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Date: Sat, 18 Feb 2023 16:23:18 +0100
Subject: [PATCH] Update the flag when a captured block state is outdated
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 6b9b5af04fe06c3f5f20a56955bd12bd2ddb7e5c..c24944d24d6e40e853823e6e2653275553157b1f 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -615,6 +615,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags);
this.capturedBlockStates.put(pos.immutable(), blockstate);
}
+ blockstate.setFlag(flags); // Paper - update the flag also
blockstate.setData(state);
return true;
}

View file

@ -1,104 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Date: Fri, 24 Jun 2022 12:39:34 +0200
Subject: [PATCH] Add EntityFertilizeEggEvent
diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
index 76ab82553488e129882fc9beb603636bb723ec42..d3c15d029d5f003cba3c89f7ea1f3ed4f943f2bd 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
@@ -441,6 +441,10 @@ public class Turtle extends Animal {
if (entityplayer == null && this.partner.getLoveCause() != null) {
entityplayer = this.partner.getLoveCause();
}
+ // Paper start - Add EntityFertilizeEggEvent event
+ io.papermc.paper.event.entity.EntityFertilizeEggEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this.animal, this.partner);
+ if (event.isCancelled()) return;
+ // Paper end - Add EntityFertilizeEggEvent event
if (entityplayer != null) {
entityplayer.awardStat(Stats.ANIMALS_BRED);
@@ -455,7 +459,7 @@ public class Turtle extends Animal {
RandomSource randomsource = this.animal.getRandom();
if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper;
+ if(event.getExperience() > 0) this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), event.getExperience(), org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper - Add EntityFertilizeEggEvent event
}
}
diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
index 22eb0a8fc35baa04b34265b62aa29a71f3cc7343..203691417e208b9e023e5f8c3b76993db2747ba8 100644
--- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java
@@ -242,7 +242,12 @@ public class Frog extends Animal implements VariantHolder<FrogVariant> {
@Override
public void spawnChildFromBreeding(ServerLevel world, Animal other) {
- this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob)null);
+ // Paper start - Add EntityFertilizeEggEvent event
+ final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other);
+ if (result.isCancelled()) return;
+
+ this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob)null, result.getExperience()); // Paper - use craftbukkit call that takes experience amount
+ // Paper end - Add EntityFertilizeEggEvent event
this.getBrain().setMemory(MemoryModuleType.IS_PREGNANT, Unit.INSTANCE);
}
diff --git a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java
index 3de0424a18e0a3b0cd2f755adfa859e474d5c643..94965855233509cbe48cebd690a83ef29cd0c27a 100644
--- a/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java
+++ b/src/main/java/net/minecraft/world/entity/animal/sniffer/Sniffer.java
@@ -350,11 +350,16 @@ public class Sniffer extends Animal {
@Override
public void spawnChildFromBreeding(ServerLevel world, Animal other) {
+ // Paper start - Add EntityFertilizeEggEvent event
+ final io.papermc.paper.event.entity.EntityFertilizeEggEvent result = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityFertilizeEggEvent(this, other);
+ if (result.isCancelled()) return;
+ // Paper end - Add EntityFertilizeEggEvent event
+
ItemStack itemstack = new ItemStack(Items.SNIFFER_EGG);
ItemEntity entityitem = new ItemEntity(world, this.position().x(), this.position().y(), this.position().z(), itemstack);
entityitem.setDefaultPickUpDelay();
- this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null);
+ this.finalizeSpawnChildFromBreeding(world, other, (AgeableMob) null, result.getExperience()); // Paper - Add EntityFertilizeEggEvent event
if (this.spawnAtLocation(entityitem) != null) { // Paper - call EntityDropItemEvent
this.playSound(SoundEvents.SNIFFER_EGG_PLOP, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 0.5F);
} // Paper
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index ee382cae3feca1de40d95faf6af023c8a7df05b9..3362ded586f723ef1f89ad6dfa872ae468f92933 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -2047,4 +2047,29 @@ public class CraftEventFactory {
return event.callEvent();
}
// Paper end
+
+ // Paper start - add EntityFertilizeEggEvent
+ /**
+ * Calls the io.papermc.paper.event.entity.EntityFertilizeEggEvent.
+ * If the event is cancelled, this method also resets the love on both the {@code breeding} and {@code other} entity.
+ *
+ * @param breeding the entity on which #spawnChildFromBreeding was called.
+ * @param other the partner of the entity.
+ * @return the event after it was called. The instance may be used to retrieve the experience of the event.
+ */
+ public static io.papermc.paper.event.entity.EntityFertilizeEggEvent callEntityFertilizeEggEvent(net.minecraft.world.entity.animal.Animal breeding,
+ net.minecraft.world.entity.animal.Animal other) {
+ net.minecraft.server.level.ServerPlayer serverPlayer = breeding.getLoveCause();
+ if (serverPlayer == null) serverPlayer = other.getLoveCause();
+ final int experience = breeding.getRandom().nextInt(7) + 1; // From Animal#spawnChildFromBreeding(ServerLevel, Animal)
+
+ final io.papermc.paper.event.entity.EntityFertilizeEggEvent event = new io.papermc.paper.event.entity.EntityFertilizeEggEvent((org.bukkit.entity.LivingEntity) breeding.getBukkitEntity(), (org.bukkit.entity.LivingEntity) other.getBukkitEntity(), serverPlayer == null ? null : serverPlayer.getBukkitEntity(), breeding.breedItem == null ? null : org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(breeding.breedItem).clone(), experience);
+ if (!event.callEvent()) {
+ breeding.resetLove();
+ other.resetLove(); // stop the pathfinding to avoid infinite loop
+ }
+
+ return event;
+ }
+ // Paper end - add EntityFertilizeEggEvent
}

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 10 Oct 2021 18:18:01 -0700
Subject: [PATCH] Fix HumanEntity#drop not updating the client inv
== AT ==
public net.minecraft.server.level.ServerPlayer containerSynchronizer
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
index 50f2a94c5f2e9f7c08cea137d8d84d65e2c41326..5fe9a0985432ac6cdd28a2a138854a24f10e42ba 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
@@ -755,8 +755,15 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
// Paper end
@Override
public boolean dropItem(boolean dropAll) {
- if (!(this.getHandle() instanceof ServerPlayer)) return false;
- return ((ServerPlayer) this.getHandle()).drop(dropAll);
+ // Paper start - notify client of remote slot change
+ if (!(this.getHandle() instanceof ServerPlayer player)) return false;
+ boolean success = player.drop(dropAll);
+ if (!success) return false;
+ final net.minecraft.world.entity.player.Inventory inv = player.getInventory();
+ final java.util.OptionalInt optionalSlot = player.containerMenu.findSlot(inv, inv.selected);
+ optionalSlot.ifPresent(slot -> player.containerSynchronizer.sendSlotChange(player.containerMenu, slot, inv.getSelected()));
+ return true;
+ // Paper end
}
@Override

View file

@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Noah van der Aa <ndvdaa@gmail.com>
Date: Sun, 8 Aug 2021 19:56:02 +0200
Subject: [PATCH] Add CompostItemEvent and EntityCompostItemEvent
diff --git a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java
index 38cb52d185e543c4df9eebfcd856df6fa80ba0ed..10d3912ef043eefdf89105332e29b0d2bf4a5539 100644
--- a/src/main/java/net/minecraft/world/level/block/ComposterBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/ComposterBlock.java
@@ -321,7 +321,21 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder {
int i = (Integer) iblockdata.getValue(ComposterBlock.LEVEL);
float f = ComposterBlock.COMPOSTABLES.getFloat(itemstack.getItem());
- if ((i != 0 || f <= 0.0F) && rand >= (double) f) {
+ // Paper start
+ boolean willRaiseLevel = !((i != 0 || f <= 0.0F) && rand >= (double) f);
+ final io.papermc.paper.event.block.CompostItemEvent event;
+ if (entity == null) {
+ event = new io.papermc.paper.event.block.CompostItemEvent(org.bukkit.craftbukkit.block.CraftBlock.at(generatoraccess, blockposition), itemstack.getBukkitStack(), willRaiseLevel);
+ } else {
+ event = new io.papermc.paper.event.entity.EntityCompostItemEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(generatoraccess, blockposition), itemstack.getBukkitStack(), willRaiseLevel);
+ }
+ if (!event.callEvent()) { // check for cancellation of entity event (non entity event can't be cancelled cause of hoppers)
+ return null;
+ }
+ willRaiseLevel = event.willRaiseLevel();
+
+ if (!willRaiseLevel) {
+ // Paper end
return iblockdata;
} else {
int j = i + 1;
@@ -471,6 +485,11 @@ public class ComposterBlock extends Block implements WorldlyContainerHolder {
this.changed = true;
BlockState iblockdata = ComposterBlock.addItem((Entity) null, this.state, this.level, this.pos, itemstack);
+ // Paper start
+ if (iblockdata == null) {
+ return;
+ }
+ // Paper end
this.level.levelEvent(1500, this.pos, iblockdata != this.state ? 1 : 0);
this.removeItemNoUpdate(0);
}

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 5 Mar 2023 14:38:21 -0800
Subject: [PATCH] Correctly handle ArmorStand invisibility
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java
index 273f3c029f878c8a30e4f0911d79195c023d3442..dc26be80f2c1f058451c0d446165bc78a0ff8c47 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftArmorStand.java
@@ -152,6 +152,14 @@ public class CraftArmorStand extends CraftLivingEntity implements ArmorStand {
this.getHandle().noPhysics = !gravity;
}
+ // Paper start - Armor Stand has its own invisible field
+ @Override
+ public void setInvisible(final boolean invisible) {
+ this.getHandle().setInvisible(invisible);
+ super.setInvisible(invisible);
+ }
+ // Paper end
+
@Override
public boolean isVisible() {
return !this.getHandle().isInvisible();

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 16 Mar 2023 10:04:17 +0100
Subject: [PATCH] Fix advancement triggers for entity damage
Changes the Interaction entity's trigger to use the vanilla
generic damage source
Fixes a couple places where the original damage and modified damage
were passed in the reverse order to the advancement triggers
diff --git a/src/main/java/net/minecraft/world/entity/Interaction.java b/src/main/java/net/minecraft/world/entity/Interaction.java
index f054d67a637b204de604fadc0d321f5c9816d808..fc5f1e1b445f0a55a35a31d58a90920a80275662 100644
--- a/src/main/java/net/minecraft/world/entity/Interaction.java
+++ b/src/main/java/net/minecraft/world/entity/Interaction.java
@@ -160,7 +160,7 @@ public class Interaction extends Entity implements Attackable, Targeting {
if (entityhuman instanceof ServerPlayer) {
ServerPlayer entityplayer = (ServerPlayer) entityhuman;
- CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(entityplayer, this, source, (float) event.getFinalDamage(), 1.0F, false); // CraftBukkit
+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger(entityplayer, this, entityhuman.damageSources().generic(), 1.0F, (float) event.getFinalDamage(), false); // CraftBukkit // Paper - use correct source and fix taken/dealt param order
}
return !this.getResponse();
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 634d272b71c464b9279a7e3ba83e9eacfcff580b..cf3173c3b3d3362040eb57ee39221e24a5bc5221 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2273,7 +2273,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
// Duplicate triggers if blocking
if (event.getDamage(DamageModifier.BLOCKING) < 0) {
if (this instanceof ServerPlayer) {
- CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damagesource, f, originalDamage, true);
+ CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damagesource, originalDamage, f, true); // Paper - fix taken/dealt param order
f2 = (float) -event.getDamage(DamageModifier.BLOCKING);
if (f2 > 0.0F && f2 < 3.4028235E37F) {
((ServerPlayer) this).awardStat(Stats.DAMAGE_BLOCKED_BY_SHIELD, Math.round(originalDamage * 10.0F));
@@ -2281,7 +2281,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
if (damagesource.getEntity() instanceof ServerPlayer) {
- CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) damagesource.getEntity(), this, damagesource, f, originalDamage, true);
+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) damagesource.getEntity(), this, damagesource, originalDamage, f, true); // Paper - fix taken/dealt param order
}
return false;

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Thu, 16 Mar 2023 16:27:50 +0100
Subject: [PATCH] Fix text display error on spawn
diff --git a/src/main/java/net/minecraft/world/entity/Display.java b/src/main/java/net/minecraft/world/entity/Display.java
index f7eeccbcb4c119f46ebb82284a109f48008c68cd..2a5a4027e5d0d9d48a727834f3f5af65ea83aa23 100644
--- a/src/main/java/net/minecraft/world/entity/Display.java
+++ b/src/main/java/net/minecraft/world/entity/Display.java
@@ -694,7 +694,7 @@ public abstract class Display extends Entity {
Logger logger = Display.LOGGER;
Objects.requireNonNull(logger);
- Optional<Display.TextDisplay.Align> optional = dataresult.resultOrPartial(Util.prefix("Display entity", logger::error)).map(Pair::getFirst);
+ Optional<Display.TextDisplay.Align> optional = dataresult.result().map(Pair::getFirst); // Paper - hide error message
if (optional.isPresent()) {
byte b1;

View file

@ -1,61 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 15 Mar 2023 18:29:45 -0700
Subject: [PATCH] Fix certain inventories returning null Locations
Wandering Trader, AbstractHorse, Beacon and Composter inventories returned null locations
when a block or entity location is readily available
Co-authored-by: Lukas Planz <lukas.planz@web.de>
diff --git a/src/main/java/net/minecraft/world/SimpleContainer.java b/src/main/java/net/minecraft/world/SimpleContainer.java
index e938e46a142f3764f8224a1fd035e7d541b59c56..9d1ee40456a8d7001eee654a62e62cab2626305a 100644
--- a/src/main/java/net/minecraft/world/SimpleContainer.java
+++ b/src/main/java/net/minecraft/world/SimpleContainer.java
@@ -63,6 +63,16 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
@Override
public Location getLocation() {
+ // Paper start
+ // When the block inventory does not have a tile state that implements getLocation, e. g. composters
+ if (this.bukkitOwner instanceof org.bukkit.inventory.BlockInventoryHolder blockInventoryHolder) {
+ return blockInventoryHolder.getBlock().getLocation();
+ }
+ // When the bukkit owner is a bukkit entity, but does not implement Container itself, e. g. horses
+ if (this.bukkitOwner instanceof org.bukkit.entity.Entity entity) {
+ return entity.getLocation();
+ }
+ // Paper end
return null;
}
diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java
index f984af71fc034e09147fa339bd5f260a7466e127..46fd2f45923366c38b77270a45c80b31250ae37e 100644
--- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java
@@ -49,6 +49,12 @@ public class BeaconMenu extends AbstractContainerMenu {
public int getMaxStackSize() {
return 1;
}
+ // Paper start
+ @Override
+ public org.bukkit.Location getLocation() {
+ return context.getLocation();
+ }
+ // Paper end
};
checkContainerDataCount(propertyDelegate, 3);
this.beaconData = propertyDelegate;
diff --git a/src/main/java/net/minecraft/world/inventory/MerchantContainer.java b/src/main/java/net/minecraft/world/inventory/MerchantContainer.java
index 083e50e27685f441ede4c75e913d671fe45d1d15..98cbcf67d8fdb1c80fb7ba8ba7734821e2818da6 100644
--- a/src/main/java/net/minecraft/world/inventory/MerchantContainer.java
+++ b/src/main/java/net/minecraft/world/inventory/MerchantContainer.java
@@ -65,7 +65,7 @@ public class MerchantContainer implements Container {
@Override
public Location getLocation() {
- return (this.merchant instanceof Villager) ? ((Villager) this.merchant).getBukkitEntity().getLocation() : null;
+ return (this.merchant instanceof AbstractVillager) ? ((AbstractVillager) this.merchant).getBukkitEntity().getLocation() : null; // Paper
}
// CraftBukkit end

View file

@ -1,72 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 17 Oct 2021 15:39:48 -0400
Subject: [PATCH] Add Shearable API
diff --git a/src/main/java/io/papermc/paper/entity/PaperShearable.java b/src/main/java/io/papermc/paper/entity/PaperShearable.java
new file mode 100644
index 0000000000000000000000000000000000000000..bcf254e3c81cf1e401bddc850fb24ad29dcc127c
--- /dev/null
+++ b/src/main/java/io/papermc/paper/entity/PaperShearable.java
@@ -0,0 +1,21 @@
+package io.papermc.paper.entity;
+
+import io.papermc.paper.adventure.PaperAdventure;
+import net.kyori.adventure.sound.Sound;
+import net.minecraft.world.entity.Shearable;
+import org.jetbrains.annotations.NotNull;
+
+public interface PaperShearable extends io.papermc.paper.entity.Shearable {
+
+ Shearable getHandle();
+
+ @Override
+ default boolean readyToBeSheared() {
+ return this.getHandle().readyForShearing();
+ }
+
+ @Override
+ default void shear(@NotNull Sound.Source source) {
+ this.getHandle().shear(PaperAdventure.asVanilla(source));
+ }
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java
index 3e0049c2442c5941e02da0b0fb643784746cb2a1..1efc208dbb00b693de0c1d883e90b310cbf253e7 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMushroomCow.java
@@ -5,7 +5,7 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.MushroomCow.Variant;
-public class CraftMushroomCow extends CraftCow implements MushroomCow {
+public class CraftMushroomCow extends CraftCow implements MushroomCow, io.papermc.paper.entity.PaperShearable { // Paper
public CraftMushroomCow(CraftServer server, net.minecraft.world.entity.animal.MushroomCow entity) {
super(server, entity);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java
index c83f16868571ab4724201e9369ab8d90d0e280c5..19e8fc7fa6037b063bc1809c85c703996cd9b5ac 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSheep.java
@@ -4,7 +4,7 @@ import org.bukkit.DyeColor;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Sheep;
-public class CraftSheep extends CraftAnimals implements Sheep {
+public class CraftSheep extends CraftAnimals implements Sheep, io.papermc.paper.entity.PaperShearable { // Paper
public CraftSheep(CraftServer server, net.minecraft.world.entity.animal.Sheep entity) {
super(server, entity);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
index 5d2e0fb911265f1184de5434464378ffba98d379..e4a14cdfeb91a3d32e622d27d612605b1bca08e2 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSnowman.java
@@ -4,7 +4,7 @@ import net.minecraft.world.entity.animal.SnowGolem;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Snowman;
-public class CraftSnowman extends CraftGolem implements Snowman, com.destroystokyo.paper.entity.CraftRangedEntity<SnowGolem> { // Paper
+public class CraftSnowman extends CraftGolem implements Snowman, com.destroystokyo.paper.entity.CraftRangedEntity<SnowGolem>, io.papermc.paper.entity.PaperShearable { // Paper
public CraftSnowman(CraftServer server, SnowGolem entity) {
super(server, entity);
}

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 23 Feb 2023 13:19:13 -0800
Subject: [PATCH] Fix SpawnEggMeta#get/setSpawnedType
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java
index 2f65ce5d63ea4ad3a0b1b8fa47efa97b6641ef20..3ab43aab043ae59e541f708c8558ddf9bdd82f84 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSpawnEgg.java
@@ -216,6 +216,31 @@ public class CraftMetaSpawnEgg extends CraftMetaItem implements SpawnEggMeta {
throw new UnsupportedOperationException("Must change item type to set spawned type");
}
+ // Paper start
+ @Override
+ public EntityType getCustomSpawnedType() {
+ return java.util.Optional.ofNullable(this.entityTag)
+ .map(tag -> tag.getString(ENTITY_ID.NBT))
+ .flatMap(net.minecraft.world.entity.EntityType::byString)
+ .map(org.bukkit.craftbukkit.util.CraftMagicNumbers::getEntityType)
+ .orElse(null);
+ }
+
+ @Override
+ public void setCustomSpawnedType(final EntityType type) {
+ if (type == null) {
+ if (this.entityTag != null) {
+ this.entityTag.remove(ENTITY_ID.NBT);
+ }
+ } else {
+ if (this.entityTag == null) {
+ this.entityTag = new CompoundTag();
+ }
+ this.entityTag.putString(ENTITY_ID.NBT, type.key().toString());
+ }
+ }
+ // Paper end
+
@Override
boolean equalsCommon(CraftMetaItem meta) {
if (!super.equalsCommon(meta)) {

View file

@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nassim Jahnke <nassim@njahnke.dev>
Date: Sat, 18 Mar 2023 18:51:33 +0100
Subject: [PATCH] Fix chiseled bookshelf and jukebox setItem with air
diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java
index bf39b8b061dd12d33217d80a4620e13ec921fe98..fd8a38dc031621b4e1bfb74a4cdf4654c5cd2b0a 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/ChiseledBookShelfBlockEntity.java
@@ -147,7 +147,7 @@ public class ChiseledBookShelfBlockEntity extends BlockEntity implements Contain
@Override
public void setItem(int slot, ItemStack stack) {
- if (stack.is(ItemTags.BOOKSHELF_BOOKS)) {
+ if (stack.isEmpty() || stack.is(ItemTags.BOOKSHELF_BOOKS)) { // Paper
this.items.set(slot, stack);
if (level != null) this.updateState(slot); // CraftBukkit - SPIGOT-7381: check for null world
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
index 77ece220a2e204c3e66e660c639abda957bf21b9..62acd6686626c84c9fc3964af62097101e8e582f 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/JukeboxBlockEntity.java
@@ -183,6 +183,12 @@ public class JukeboxBlockEntity extends BlockEntity implements Clearable, Contai
@Override
public void setItem(int slot, ItemStack stack) {
+ // Paper start
+ if (stack.isEmpty()) {
+ this.removeItem(slot, 0);
+ return;
+ }
+ // Paper end
if (stack.is(ItemTags.MUSIC_DISCS) && this.level != null) {
this.items.set(slot, stack);
this.setHasRecordBlockState((Entity) null, true);

View file

@ -1,608 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 27 Apr 2016 22:09:52 -0400
Subject: [PATCH] Optimize Hoppers
* Removes unnecessary extra calls to .update() that are very expensive
* Lots of itemstack cloning removed. Only clone if the item is actually moved
* Return true when a plugin cancels inventory move item event instead of false, as false causes pulls to cycle through all items.
However, pushes do not exhibit the same behavior, so this is not something plugins could of been relying on.
* Add option (Default on) to cooldown hoppers when they fail to move an item due to full inventory
* Skip subsequent InventoryMoveItemEvents if a plugin does not use the item after first event fire for an iteration
* Don't check for Entities with Inventories if the block above us is also occluding (not just Inventoried)
* Remove Streams from Item Suck In and restore restore 1.12 AABB checks which is simpler and no voxel allocations (was doing TWO Item Suck ins)
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index f1b8ebb9718c8ff824d2707a0d1eb08cdcd18f39..b31470c4caeb1bd29b99bfafea90bf10d714568c 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1521,6 +1521,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
+ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper
worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
this.profiler.push(() -> {
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index cc58df88fc3788dcfb7e429ef899b3d558a931cc..b3c99bb1da54209a21b090d31713167fd9729654 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -723,10 +723,16 @@ public final class ItemStack {
}
public ItemStack copy() {
- if (this.isEmpty()) {
+ // Paper start
+ return this.copy(false);
+ }
+
+ public ItemStack copy(boolean originalItem) {
+ if (!originalItem && this.isEmpty()) {
+ // Paper end
return ItemStack.EMPTY;
} else {
- ItemStack itemstack = new ItemStack(this.getItem(), this.count);
+ ItemStack itemstack = new ItemStack(originalItem ? this.item : this.getItem(), this.count); // Paper
itemstack.setPopTime(this.getPopTime());
if (this.tag != null) {
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
index 5bdad1866386908b9fef74d15862eb107fabe68f..370a25d2deb54f10a35ee24d9e7e92fbfde60edf 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -26,6 +26,7 @@ import co.aikar.timings.MinecraftTimings; // Paper
import co.aikar.timings.Timing; // Paper
public abstract class BlockEntity {
+ static boolean ignoreTileUpdates; // Paper
public Timing tickTimer = MinecraftTimings.getTileEntityTimings(this); // Paper
// CraftBukkit start - data containers
@@ -161,6 +162,7 @@ public abstract class BlockEntity {
public void setChanged() {
if (this.level != null) {
+ if (ignoreTileUpdates) return; // Paper
BlockEntity.setChanged(this.level, this.worldPosition, this.blockState);
}
diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 6907e647ef4d3f5c9c46edb4cf0905844dd1cea9..b11f51762ca289d99eaa49e66e31e58595bcea4e 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -193,6 +193,202 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
return false;
}
+ // Paper start - Optimize Hoppers
+ private static boolean skipPullModeEventFire;
+ private static boolean skipPushModeEventFire;
+ public static boolean skipHopperEvents;
+
+ private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) {
+ skipPushModeEventFire = skipHopperEvents;
+ boolean foundItem = false;
+ for (int i = 0; i < hopper.getContainerSize(); ++i) {
+ final ItemStack item = hopper.getItem(i);
+ if (!item.isEmpty()) {
+ foundItem = true;
+ ItemStack origItemStack = item;
+ ItemStack movedItem = origItemStack;
+
+ final int originalItemCount = origItemStack.getCount();
+ final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
+ origItemStack.setCount(movedItemCount);
+
+ // We only need to fire the event once to give protection plugins a chance to cancel this event
+ // Because nothing uses getItem, every event call should end up the same result.
+ if (!skipPushModeEventFire) {
+ movedItem = callPushMoveEvent(destination, movedItem, hopper);
+ if (movedItem == null) { // cancelled
+ origItemStack.setCount(originalItemCount);
+ return false;
+ }
+ }
+
+ final ItemStack remainingItem = addItem(hopper, destination, movedItem, direction);
+ final int remainingItemCount = remainingItem.getCount();
+ if (remainingItemCount != movedItemCount) {
+ origItemStack = origItemStack.copy(true);
+ origItemStack.setCount(originalItemCount);
+ if (!origItemStack.isEmpty()) {
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
+ }
+ hopper.setItem(i, origItemStack);
+ destination.setChanged();
+ return true;
+ }
+ origItemStack.setCount(originalItemCount);
+ }
+ }
+ if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
+ hopper.setCooldown(level.spigotConfig.hopperTransfer);
+ }
+ return false;
+ }
+
+ private static boolean hopperPull(final Level level, final Hopper hopper, final Container container, ItemStack origItemStack, final int i) {
+ ItemStack movedItem = origItemStack;
+ final int originalItemCount = origItemStack.getCount();
+ final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
+ container.setChanged(); // original logic always marks source inv as changed even if no move happens.
+ movedItem.setCount(movedItemCount);
+
+ if (!skipPullModeEventFire) {
+ movedItem = callPullMoveEvent(hopper, container, movedItem);
+ if (movedItem == null) { // cancelled
+ origItemStack.setCount(originalItemCount);
+ // Drastically improve performance by returning true.
+ // No plugin could of relied on the behavior of false as the other call
+ // site for IMIE did not exhibit the same behavior
+ return true;
+ }
+ }
+
+ final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
+ final int remainingItemCount = remainingItem.getCount();
+ if (remainingItemCount != movedItemCount) {
+ origItemStack = origItemStack.copy(true);
+ origItemStack.setCount(originalItemCount);
+ if (!origItemStack.isEmpty()) {
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
+ }
+
+ ignoreTileUpdates = true;
+ container.setItem(i, origItemStack);
+ ignoreTileUpdates = false;
+ container.setChanged();
+ return true;
+ }
+ origItemStack.setCount(originalItemCount);
+
+ if (level.paperConfig().hopper.cooldownWhenFull) {
+ cooldownHopper(hopper);
+ }
+
+ return false;
+ }
+
+ @Nullable
+ private static ItemStack callPushMoveEvent(Container iinventory, ItemStack itemstack, HopperBlockEntity hopper) {
+ final Inventory destinationInventory = getInventory(iinventory);
+ final InventoryMoveItemEvent event = new InventoryMoveItemEvent(hopper.getOwner(false).getInventory(),
+ CraftItemStack.asCraftMirror(itemstack), destinationInventory, true);
+ final boolean result = event.callEvent();
+ if (!event.calledGetItem && !event.calledSetItem) {
+ skipPushModeEventFire = true;
+ }
+ if (!result) {
+ cooldownHopper(hopper);
+ return null;
+ }
+
+ if (event.calledSetItem) {
+ return CraftItemStack.asNMSCopy(event.getItem());
+ } else {
+ return itemstack;
+ }
+ }
+
+ @Nullable
+ private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) {
+ final Inventory sourceInventory = getInventory(container);
+ final Inventory destination = getInventory(hopper);
+
+ // Mirror is safe as no plugins ever use this item
+ final InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, CraftItemStack.asCraftMirror(itemstack), destination, false);
+ final boolean result = event.callEvent();
+ if (!event.calledGetItem && !event.calledSetItem) {
+ skipPullModeEventFire = true;
+ }
+ if (!result) {
+ cooldownHopper(hopper);
+ return null;
+ }
+
+ if (event.calledSetItem) {
+ return CraftItemStack.asNMSCopy(event.getItem());
+ } else {
+ return itemstack;
+ }
+ }
+
+ private static Inventory getInventory(final Container container) {
+ final Inventory sourceInventory;
+ if (container instanceof CompoundContainer compoundContainer) {
+ // Have to special-case large chests as they work oddly
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
+ } else if (container instanceof BlockEntity blockEntity) {
+ sourceInventory = blockEntity.getOwner(false).getInventory();
+ } else if (container.getOwner() != null) {
+ sourceInventory = container.getOwner().getInventory();
+ } else {
+ sourceInventory = new CraftInventory(container);
+ }
+ return sourceInventory;
+ }
+
+ private static void cooldownHopper(final Hopper hopper) {
+ if (hopper instanceof HopperBlockEntity blockEntity && blockEntity.getLevel() != null) {
+ blockEntity.setCooldown(blockEntity.getLevel().spigotConfig.hopperTransfer);
+ }
+ }
+
+ private static boolean allMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
+ if (iinventory instanceof WorldlyContainer) {
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) {
+ if (!test.test(iinventory.getItem(i), i)) {
+ return false;
+ }
+ }
+ } else {
+ int size = iinventory.getContainerSize();
+ for (int i = 0; i < size; i++) {
+ if (!test.test(iinventory.getItem(i), i)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private static boolean anyMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
+ if (iinventory instanceof WorldlyContainer) {
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) {
+ if (test.test(iinventory.getItem(i), i)) {
+ return true;
+ }
+ }
+ } else {
+ int size = iinventory.getContainerSize();
+ for (int i = 0; i < size; i++) {
+ if (test.test(iinventory.getItem(i), i)) {
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+ private static final java.util.function.BiPredicate<ItemStack, Integer> STACK_SIZE_TEST = (itemstack, i) -> itemstack.getCount() >= itemstack.getMaxStackSize();
+ private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemstack, i) -> itemstack.isEmpty();
+ // Paper end
+
private static boolean ejectItems(Level world, BlockPos blockposition, BlockState iblockdata, Container iinventory, HopperBlockEntity hopper) { // CraftBukkit
Container iinventory1 = HopperBlockEntity.getAttachedContainer(world, blockposition, iblockdata);
@@ -204,46 +400,49 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (HopperBlockEntity.isFullContainer(iinventory1, enumdirection)) {
return false;
} else {
- for (int i = 0; i < iinventory.getContainerSize(); ++i) {
- if (!iinventory.getItem(i).isEmpty()) {
- ItemStack itemstack = iinventory.getItem(i).copy();
- // ItemStack itemstack1 = addItem(iinventory, iinventory1, iinventory.removeItem(i, 1), enumdirection);
-
- // CraftBukkit start - Call event when pushing items into other inventories
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
-
- Inventory destinationInventory;
- // Have to special case large chests as they work oddly
- if (iinventory1 instanceof CompoundContainer) {
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory1);
- } else if (iinventory1.getOwner() != null) {
- destinationInventory = iinventory1.getOwner().getInventory();
- } else {
- destinationInventory = new CraftInventory(iinventory);
- }
-
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
- world.getCraftServer().getPluginManager().callEvent(event);
- if (event.isCancelled()) {
- hopper.setItem(i, itemstack);
- hopper.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
- return false;
- }
- int origCount = event.getItem().getAmount(); // Spigot
- ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, iinventory1, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
+ // Paper start - replace logic; MAKE SURE TO CHECK FOR DIFFS ON UPDATES
+ return hopperPush(world, iinventory1, enumdirection, hopper);
+ // for (int i = 0; i < iinventory.getContainerSize(); ++i) {
+ // if (!iinventory.getItem(i).isEmpty()) {
+ // ItemStack itemstack = iinventory.getItem(i).copy();
+ // // ItemStack itemstack1 = addItem(iinventory, iinventory1, iinventory.removeItem(i, 1), enumdirection);
+
+ // // CraftBukkit start - Call event when pushing items into other inventories
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
+
+ // Inventory destinationInventory;
+ // // Have to special case large chests as they work oddly
+ // if (iinventory1 instanceof CompoundContainer) {
+ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory1);
+ // } else if (iinventory1.getOwner() != null) {
+ // destinationInventory = iinventory1.getOwner().getInventory();
+ // } else {
+ // destinationInventory = new CraftInventory(iinventory);
+ // }
+
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
+ // world.getCraftServer().getPluginManager().callEvent(event);
+ // if (event.isCancelled()) {
+ // hopper.setItem(i, itemstack);
+ // hopper.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
+ // return false;
+ // }
+ // int origCount = event.getItem().getAmount(); // Spigot
+ // ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, iinventory1, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
// CraftBukkit end
- if (itemstack1.isEmpty()) {
- iinventory1.setChanged();
- return true;
- }
+ // if (itemstack1.isEmpty()) {
+ // iinventory1.setChanged();
+ // return true;
+ // }
- itemstack.shrink(origCount - itemstack1.getCount()); // Spigot
- iinventory.setItem(i, itemstack);
- }
- }
+ // itemstack.shrink(origCount - itemstack1.getCount()); // Spigot
+ // iinventory.setItem(i, itemstack);
+ // }
+ // }
- return false;
+ // return false;
+ // Paper end
}
}
}
@@ -253,17 +452,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
private static boolean isFullContainer(Container inventory, Direction direction) {
- return HopperBlockEntity.getSlots(inventory, direction).allMatch((i) -> {
- ItemStack itemstack = inventory.getItem(i);
-
- return itemstack.getCount() >= itemstack.getMaxStackSize();
- });
+ return allMatch(inventory, direction, STACK_SIZE_TEST); // Paper - no streams
}
private static boolean isEmptyContainer(Container inv, Direction facing) {
- return HopperBlockEntity.getSlots(inv, facing).allMatch((i) -> {
- return inv.getItem(i).isEmpty();
- });
+ return allMatch(inv, facing, IS_EMPTY_TEST);
}
public static boolean suckInItems(Level world, Hopper hopper) {
@@ -272,8 +465,16 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (iinventory != null) {
Direction enumdirection = Direction.DOWN;
- return HopperBlockEntity.isEmptyContainer(iinventory, enumdirection) ? false : HopperBlockEntity.getSlots(iinventory, enumdirection).anyMatch((i) -> {
- return HopperBlockEntity.a(hopper, iinventory, i, enumdirection, world); // Spigot
+ // Paper start - optimize hoppers and remove streams
+ skipPullModeEventFire = skipHopperEvents;
+ return !HopperBlockEntity.isEmptyContainer(iinventory, enumdirection) && anyMatch(iinventory, enumdirection, (item, i) -> {
+ // Logic copied from below to avoid extra getItem calls
+ if (!item.isEmpty() && canTakeItemFromContainer(hopper, iinventory, item, i, enumdirection)) {
+ return hopperPull(world, hopper, iinventory, item, i);
+ } else {
+ return false;
+ }
+ // Paper end
});
} else {
Iterator iterator = HopperBlockEntity.getItemsAtAndAbove(world, hopper).iterator();
@@ -292,48 +493,52 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
}
+ @io.papermc.paper.annotation.DoNotUse // Paper - method unused as logic is inlined above
private static boolean a(Hopper ihopper, Container iinventory, int i, Direction enumdirection, Level world) { // Spigot
ItemStack itemstack = iinventory.getItem(i);
- if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) {
- ItemStack itemstack1 = itemstack.copy();
- // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null);
- // CraftBukkit start - Call event on collection of items from inventories into the hopper
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
-
- Inventory sourceInventory;
- // Have to special case large chests as they work oddly
- if (iinventory instanceof CompoundContainer) {
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
- } else if (iinventory.getOwner() != null) {
- sourceInventory = iinventory.getOwner().getInventory();
- } else {
- sourceInventory = new CraftInventory(iinventory);
- }
-
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false);
-
- Bukkit.getServer().getPluginManager().callEvent(event);
- if (event.isCancelled()) {
- iinventory.setItem(i, itemstack1);
-
- if (ihopper instanceof HopperBlockEntity) {
- ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot
- }
-
- return false;
- }
- int origCount = event.getItem().getAmount(); // Spigot
- ItemStack itemstack2 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
- // CraftBukkit end
-
- if (itemstack2.isEmpty()) {
- iinventory.setChanged();
- return true;
- }
-
- itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot
- iinventory.setItem(i, itemstack1);
+ // Paper start - replace pull logic; MAKE SURE TO CHECK FOR DIFFS WHEN UPDATING
+ if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) { // If this logic changes, update above. this is left unused incase reflective plugins
+ return hopperPull(world, ihopper, iinventory, itemstack, i);
+ // ItemStack itemstack1 = itemstack.copy();
+ // // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null);
+ // // CraftBukkit start - Call event on collection of items from inventories into the hopper
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
+
+ // Inventory sourceInventory;
+ // // Have to special case large chests as they work oddly
+ // if (iinventory instanceof CompoundContainer) {
+ // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
+ // } else if (iinventory.getOwner() != null) {
+ // sourceInventory = iinventory.getOwner().getInventory();
+ // } else {
+ // sourceInventory = new CraftInventory(iinventory);
+ // }
+
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false);
+
+ // Bukkit.getServer().getPluginManager().callEvent(event);
+ // if (event.isCancelled()) {
+ // iinventory.setItem(i, itemstack1);
+
+ // if (ihopper instanceof HopperBlockEntity) {
+ // ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot
+ // }
+
+ // return false;
+ // }
+ // int origCount = event.getItem().getAmount(); // Spigot
+ // ItemStack itemstack2 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
+ // // CraftBukkit end
+
+ // if (itemstack2.isEmpty()) {
+ // iinventory.setChanged();
+ // return true;
+ // }
+
+ // itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot
+ // iinventory.setItem(i, itemstack1);
+ // Paper end
}
return false;
@@ -342,7 +547,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public static boolean addItem(Container inventory, ItemEntity itemEntity) {
boolean flag = false;
// CraftBukkit start
- InventoryPickupItemEvent event = new InventoryPickupItemEvent(inventory.getOwner().getInventory(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity());
+ InventoryPickupItemEvent event = new InventoryPickupItemEvent(getInventory(inventory), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); // Paper - use getInventory() to avoid snapshot creation
itemEntity.level().getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return false;
@@ -442,7 +647,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
stack = stack.split(to.getMaxStackSize());
}
// Spigot end
+ ignoreTileUpdates = true; // Paper
to.setItem(slot, stack);
+ ignoreTileUpdates = false; // Paper
stack = leftover; // Paper
flag = true;
} else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) {
@@ -516,19 +723,47 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
// CraftBukkit end
}
+ // Paper start - optimize hopper item suck in
+ static final AABB HOPPER_ITEM_SUCK_OVERALL = Hopper.SUCK.bounds();
+ static final AABB[] HOPPER_ITEM_SUCK_INDIVIDUAL = Hopper.SUCK.toAabbs().toArray(new AABB[0]);
+ // Paper end - optimize hopper item suck in
+
public static List<ItemEntity> getItemsAtAndAbove(Level world, Hopper hopper) {
- return (List) hopper.getSuckShape().toAabbs().stream().flatMap((axisalignedbb) -> {
- return world.getEntitiesOfClass(ItemEntity.class, axisalignedbb.move(hopper.getLevelX() - 0.5D, hopper.getLevelY() - 0.5D, hopper.getLevelZ() - 0.5D), EntitySelector.ENTITY_STILL_ALIVE).stream();
- }).collect(Collectors.toList());
+ // Paper start - optimize hopper item suck in
+ // eliminate multiple getEntitiesOfClass() but maintain the voxelshape collision by moving
+ // the individual AABB checks into the predicate
+ final double shiftX = hopper.getLevelX() - 0.5D;
+ final double shiftY = hopper.getLevelY() - 0.5D;
+ final double shiftZ = hopper.getLevelZ() - 0.5D;
+ return world.getEntitiesOfClass(ItemEntity.class, HOPPER_ITEM_SUCK_OVERALL.move(shiftX, shiftY, shiftZ), (final Entity entity) -> {
+ if (!entity.isAlive()) { // EntitySelector.ENTITY_STILL_ALIVE
+ return false;
+ }
+
+ for (final AABB aabb : HOPPER_ITEM_SUCK_INDIVIDUAL) {
+ if (aabb.move(shiftX, shiftY, shiftZ).intersects(entity.getBoundingBox())) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+ // Paper end - optimize hopper item suck in
}
@Nullable
public static Container getContainerAt(Level world, BlockPos pos) {
- return HopperBlockEntity.getContainerAt(world, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D);
+ return HopperBlockEntity.getContainerAt(world, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, true); // Paper
}
@Nullable
private static Container getContainerAt(Level world, double x, double y, double z) {
+ // Paper start - add optimizeEntities parameter
+ return HopperBlockEntity.getContainerAt(world, x, y, z, false);
+ }
+ @Nullable
+ private static Container getContainerAt(Level world, double x, double y, double z, final boolean optimizeEntities) {
+ // Paper end - add optimizeEntities parameter
Object object = null;
BlockPos blockposition = BlockPos.containing(x, y, z);
if ( !world.spigotConfig.hopperCanLoadChunks && !world.hasChunkAt( blockposition ) ) return null; // Spigot
@@ -548,7 +783,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
}
- if (object == null) {
+ if (object == null && (!optimizeEntities || !world.paperConfig().hopper.ignoreOccludingBlocks || !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding())) { // Paper
List<Entity> list = world.getEntities((Entity) null, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR);
if (!list.isEmpty()) {
@@ -560,7 +795,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
private static boolean canMergeItems(ItemStack first, ItemStack second) {
- return first.getCount() <= first.getMaxStackSize() && ItemStack.isSameItemSameTags(first, second);
+ return first.getCount() < first.getMaxStackSize() && first.is(second.getItem()) && first.getDamageValue() == second.getDamageValue() && ((first.isEmpty() && second.isEmpty()) || java.util.Objects.equals(first.getTag(), second.getTag())); // Paper - used to return true for full itemstacks?!
}
@Override
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
index e11618247ad889fa8fadbb2c7addd0de94caf249..081691f9710ff1115e4308f79ed49fbc38941193 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
@@ -95,12 +95,19 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
@Override
public boolean isEmpty() {
this.unpackLootTable((Player)null);
- return this.getItems().stream().allMatch(ItemStack::isEmpty);
+ // Paper start
+ for (final ItemStack itemStack : this.getItems()) {
+ if (!itemStack.isEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ // Paper end
}
@Override
public ItemStack getItem(int slot) {
- this.unpackLootTable((Player)null);
+ if (slot == 0) this.unpackLootTable((Player)null); // Paper
return this.getItems().get(slot);
}

View file

@ -1,44 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 26 Mar 2023 18:07:56 -0700
Subject: [PATCH] Fix beehives generating from using bonemeal
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index b3c99bb1da54209a21b090d31713167fd9729654..c9363f01b3c2369d5c63e50977c28a3fa760bae1 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -396,6 +396,7 @@ public final class ItemStack {
}
for (CraftBlockState blockstate : blocks) {
world.setBlock(blockstate.getPosition(),blockstate.getHandle(), blockstate.getFlag()); // SPIGOT-7248 - manual update to avoid physics where appropriate
+ if (blockstate instanceof org.bukkit.craftbukkit.block.CapturedBlockState capturedBlockState) capturedBlockState.checkTreeBlockHack(); // Paper
}
entityhuman.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CapturedBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CapturedBlockState.java
index fb6454cc64ebc549f61ad7d51efb16ef15f8384d..a3d5e319473e2f6316b3ef8edf719296e02d85a1 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CapturedBlockState.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CapturedBlockState.java
@@ -25,6 +25,12 @@ public final class CapturedBlockState extends CraftBlockState {
public boolean update(boolean force, boolean applyPhysics) {
boolean result = super.update(force, applyPhysics);
+ // Paper start
+ this.checkTreeBlockHack();
+ return result;
+ }
+ public void checkTreeBlockHack() {
+ // Paper end
// SPIGOT-5537: Horrible hack to manually add bees given World.captureTreeGeneration does not support tiles
if (this.treeBlock && getType() == Material.BEE_NEST) {
WorldGenLevel generatoraccessseed = this.world.getHandle();
@@ -47,7 +53,7 @@ public final class CapturedBlockState extends CraftBlockState {
// End copied block
}
- return result;
+ // Paper
}
public static CapturedBlockState getBlockState(Level world, BlockPos pos, int flag) {

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 19 Mar 2023 20:36:22 -0700
Subject: [PATCH] Fix crash relating to bad recipes in furnace-like tile
entities
diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
index 5ccc419b904aec590c5624438da61ca6724b20d6..448fa4f4f200430d6ce3051763c7ceb697696146 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -642,6 +642,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
Entry<ResourceLocation> entry = (Entry) objectiterator.next();
worldserver.getRecipeManager().byKey((ResourceLocation) entry.getKey()).ifPresent((irecipe) -> {
+ if (!(irecipe instanceof AbstractCookingRecipe)) return; // Paper - don't process non-cooking recipes
list.add(irecipe);
AbstractFurnaceBlockEntity.createExperience(worldserver, vec3d, entry.getIntValue(), ((AbstractCookingRecipe) irecipe).getExperience(), blockposition, entityplayer, itemstack, amount); // CraftBukkit
});

View file

@ -1,18 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Thu, 30 Mar 2023 03:13:58 +0100
Subject: [PATCH] Treat sequence violations like they should be
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 5cb45e6e5f73996b2a603589b8571cf0155a42c5..419979939efcf83f03edab522b4360c9d2c03fe3 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2129,6 +2129,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
public void ackBlockChangesUpTo(int sequence) {
if (sequence < 0) {
+ this.disconnect("Expected packet sequence nr >= 0", org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper
throw new IllegalArgumentException("Expected packet sequence nr >= 0");
} else {
this.ackBlockChangesUpTo = Math.max(sequence, this.ackBlockChangesUpTo);

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 1 Dec 2022 12:42:18 -0800
Subject: [PATCH] remove duplicate animate packet for records
diff --git a/src/main/java/net/minecraft/world/item/RecordItem.java b/src/main/java/net/minecraft/world/item/RecordItem.java
index af6d00adfe9b528f9854fbed174f7ae1f44522a6..a088111762fd36d4e6a8303e964b06c610590b44 100644
--- a/src/main/java/net/minecraft/world/item/RecordItem.java
+++ b/src/main/java/net/minecraft/world/item/RecordItem.java
@@ -46,7 +46,7 @@ public class RecordItem extends Item {
ItemStack itemstack = context.getItemInHand();
if (!world.isClientSide) {
- if (true) return InteractionResult.SUCCESS; // CraftBukkit - handled in ItemStack
+ if (true) return InteractionResult.sidedSuccess(world.isClientSide); // CraftBukkit - handled in ItemStack // Paper - fix duplicate animate packet
Player entityhuman = context.getPlayer();
BlockEntity tileentity = world.getBlockEntity(blockposition);

View file

@ -1,59 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Mon, 3 Apr 2023 08:55:52 +0100
Subject: [PATCH] Prevent causing expired keys from impacting new joins
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
index 23e0e6937e28f09271a4ec7c35e0076a576cf3d3..4aa8b483841028fbcc43f9ed47730881263e5065 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
@@ -94,7 +94,13 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet<ClientGamePacke
INITIALIZE_CHAT((serialized, buf) -> {
serialized.chatSession = buf.readNullable(RemoteChatSession.Data::read);
}, (buf, entry) -> {
- buf.writeNullable(entry.chatSession, RemoteChatSession.Data::write);
+ // Paper start
+ RemoteChatSession.Data chatSession = entry.chatSession;
+ if (chatSession != null && chatSession.profilePublicKey().hasExpired()) {
+ chatSession = null;
+ }
+ buf.writeNullable(chatSession, RemoteChatSession.Data::write);
+ // Paper end
}),
UPDATE_GAME_MODE((serialized, buf) -> {
serialized.gameMode = GameType.byId(buf.readVarInt());
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 419979939efcf83f03edab522b4360c9d2c03fe3..f6ba77a7c43a6a030fe4073ba7ee2970e7d774f3 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -298,6 +298,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
private final AtomicReference<Instant> lastChatTimeStamp;
@Nullable
private RemoteChatSession chatSession;
+ private boolean hasLoggedExpiry = false; // Paper
private SignedMessageChain.Decoder signedMessageDecoder;
private final LastSeenMessagesValidator lastSeenMessages;
private final MessageSignatureCache messageSignatureCache;
@@ -438,6 +439,13 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
this.disconnect(Component.translatable("multiplayer.disconnect.idling"), org.bukkit.event.player.PlayerKickEvent.Cause.IDLING); // Paper - kick event cause
}
+ // Paper start
+ if (!hasLoggedExpiry && this.chatSession != null && this.chatSession.profilePublicKey().data().hasExpired()) {
+ LOGGER.info("Player profile key for {} has expired!", this.player.getName().getString());
+ hasLoggedExpiry = true;
+ }
+ // Paper end
+
}
public void resetPosition() {
@@ -3614,6 +3622,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
private void resetPlayerChatState(RemoteChatSession session) {
this.chatSession = session;
+ this.hasLoggedExpiry = false; // Paper
this.signedMessageDecoder = session.createMessageDecoder(this.player.getUUID());
this.chatMessageChain.append((executor) -> {
this.player.setChatSession(session);

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Wed, 5 Apr 2023 20:15:47 +0100
Subject: [PATCH] Prevent GameEvents being fired from unloaded chunks
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 37873ea2876a89ac8ea702ab0a71171e044852bc..18aac3da3c88f33b1a71a5920a8daa27e9723913 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -1782,6 +1782,11 @@ public class ServerLevel extends Level implements WorldGenLevel {
@Override
public void gameEvent(GameEvent event, Vec3 emitterPos, GameEvent.Context emitter) {
+ // Paper start
+ if (this.getChunkIfLoadedImmediately((Mth.floor(emitterPos.x) >> 4), (Mth.floor(emitterPos.z) >> 4)) == null) {
+ return;
+ }
+ // Paper end
this.gameEventDispatcher.post(event, emitterPos, emitter);
}

View file

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Sauve <paul@technove.co>
Date: Sun, 9 May 2021 16:49:49 -0500
Subject: [PATCH] Use array for gamerule storage
diff --git a/src/main/java/net/minecraft/world/level/GameRules.java b/src/main/java/net/minecraft/world/level/GameRules.java
index edd2c9d0cf5a81c779011cb4215d496a8987b784..6fa00d9239546aa82b9e92e25a33103868084c38 100644
--- a/src/main/java/net/minecraft/world/level/GameRules.java
+++ b/src/main/java/net/minecraft/world/level/GameRules.java
@@ -100,6 +100,7 @@ public class GameRules {
public static final GameRules.Key<GameRules.BooleanValue> RULE_GLOBAL_SOUND_EVENTS = GameRules.register("globalSoundEvents", GameRules.Category.MISC, GameRules.BooleanValue.create(true));
public static final GameRules.Key<GameRules.BooleanValue> RULE_DO_VINES_SPREAD = GameRules.register("doVinesSpread", GameRules.Category.UPDATES, GameRules.BooleanValue.create(true));
private final Map<GameRules.Key<?>, GameRules.Value<?>> rules;
+ private final GameRules.Value<?>[] gameruleArray; // Paper
private static <T extends GameRules.Value<T>> GameRules.Key<T> register(String name, GameRules.Category category, GameRules.Type<T> type) {
GameRules.Key<T> gamerules_gamerulekey = new GameRules.Key<>(name, category);
@@ -118,17 +119,30 @@ public class GameRules {
}
public GameRules() {
- this.rules = (Map) GameRules.GAME_RULE_TYPES.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry) -> {
+ // Paper start - use this to ensure gameruleArray is initialized
+ this((Map) GameRules.GAME_RULE_TYPES.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry) -> {
return ((GameRules.Type) entry.getValue()).createRule();
- }));
+ })));
+ // Paper end
}
private GameRules(Map<GameRules.Key<?>, GameRules.Value<?>> rules) {
this.rules = rules;
+
+ // Paper start
+ int arraySize = rules.keySet().stream().mapToInt(key -> key.gameRuleIndex).max().orElse(-1) + 1;
+ GameRules.Value<?>[] values = new GameRules.Value[arraySize];
+
+ for (Entry<GameRules.Key<?>, GameRules.Value<?>> entry : rules.entrySet()) {
+ values[entry.getKey().gameRuleIndex] = entry.getValue();
+ }
+
+ this.gameruleArray = values;
+ // Paper end
}
public <T extends GameRules.Value<T>> T getRule(GameRules.Key<T> key) {
- return (T) this.rules.get(key); // CraftBukkit - decompile error
+ return key == null ? null : (T) this.gameruleArray[key.gameRuleIndex]; // Paper
}
public CompoundTag createTag() {
@@ -187,6 +201,10 @@ public class GameRules {
}
public static final class Key<T extends GameRules.Value<T>> {
+ // Paper start
+ private static int lastGameRuleIndex = 0;
+ public final int gameRuleIndex = lastGameRuleIndex++;
+ // Paper end
final String id;
private final GameRules.Category category;

View file

@ -1,33 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sun, 9 Apr 2023 21:11:58 -0700
Subject: [PATCH] Fix a couple of upstream bed issues
Upstream incorrectly skipped explosion logic if
the bed was occupied and added a "feature" where
if you set your spawn in a respawn anchor world
but then replaced it with a bed, you could respawn
at the bed in that world.
diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java
index 69839965926c511b6396a0041b6e7295ebf5209b..d40500f9a807cab0b2fb6fa9032f33f4fb74c895 100644
--- a/src/main/java/net/minecraft/world/level/block/BedBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java
@@ -99,6 +99,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock
world.explode((Entity) null, world.damageSources().badRespawnPointExplosion(vec3d, explodedBlockState), (ExplosionDamageCalculator) null, vec3d, 5.0F, true, Level.ExplosionInteraction.BLOCK);
return InteractionResult.SUCCESS;
} else if ((Boolean) state.getValue(BedBlock.OCCUPIED)) {
+ if (!BedBlock.canSetSpawn(world)) return this.explodeBed(state, world, pos); // Paper - check explode first
if (!this.kickVillagerOutOfBed(world, pos)) {
player.displayClientMessage(Component.translatable("block.minecraft.bed.occupied"), true);
}
@@ -156,8 +157,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock
// CraftBukkit end
public static boolean canSetSpawn(Level world) {
- // CraftBukkit - moved world and biome check into EntityHuman
- return true || world.dimensionType().bedWorks();
+ return world.dimensionType().bedWorks(); // Paper - actually check if the bed works
}
private boolean kickVillagerOutOfBed(Level world, BlockPos pos) {

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Warrior <50800980+Warriorrrr@users.noreply.github.com>
Date: Fri, 7 Apr 2023 20:11:17 +0200
Subject: [PATCH] Fix demo flag not enabling demo mode
https://github.com/PaperMC/Paper/issues/9046
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index c1a492827bbde63dd464402767d4c6a2cdf689eb..a7ebf851a65231074c89a24f30de4ac2fb5b63e4 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -312,7 +312,7 @@ public class Main {
/*
dedicatedserver1.setSingleplayerProfile(optionset.has(optionspec8) ? new GameProfile((UUID) null, (String) optionset.valueOf(optionspec8)) : null);
dedicatedserver1.setPort((Integer) optionset.valueOf(optionspec11));
- dedicatedserver1.setDemo(optionset.has(optionspec2));
+ */dedicatedserver1.setDemo(optionset.has("demo"));/* // Paper - Restore setting the demo mode
dedicatedserver1.setId((String) optionset.valueOf(optionspec12));
*/
boolean flag1 = !optionset.has("nogui") && !optionset.nonOptionArguments().contains("nogui");

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: GodOfPro <1387ilia@gmail.com>
Date: Tue, 11 Apr 2023 16:31:39 +0430
Subject: [PATCH] Add Mob Experience reward API
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
index 620d918e302a00d5a6640648e3096988d15535a0..18b9b0dc70f6872a9d71c120bcd2edca531b0ac4 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java
@@ -158,4 +158,11 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob {
getHandle().setLeftHanded(leftHanded);
}
// Paper end
+
+ // Paper start
+ @Override
+ public int getPossibleExperienceReward() {
+ return getHandle().getExperienceReward();
+ }
+ // Paper end
}

View file

@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 1 May 2023 18:31:26 -0700
Subject: [PATCH] Break redstone on top of trap doors early
This logic hooks into the neighbour update which should be invoked
as a result of redstone powering the trap door.
diff --git a/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java b/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java
index aa3fdadd1cc2200adb6e0cf523c38833dc01b71b..b9e3c9cd709d42bced85436720ccc7b9c7e49552 100644
--- a/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TrapDoorBlock.java
@@ -124,7 +124,26 @@ public class TrapDoorBlock extends HorizontalDirectionalBlock implements SimpleW
flag1 = eventRedstone.getNewCurrent() > 0;
}
// CraftBukkit end
- if ((Boolean) state.getValue(TrapDoorBlock.OPEN) != flag1) {
+ boolean open = (Boolean) state.getValue(TrapDoorBlock.OPEN) != flag1; // Paper - break redstone on trapdoors early
+ // Paper start - break redstone on trapdoors early
+ // note: this must run before any state for this block/its neighborus are written to the world
+ // we allow the redstone event to fire so that plugins can block
+ if (flag1 && open) { // if we are now powered and it caused the trap door to open
+ // in this case, first check for the redstone on top first
+ BlockPos abovePos = pos.above();
+ BlockState above = world.getBlockState(abovePos);
+ if (above.getBlock() instanceof RedStoneWireBlock) {
+ world.setBlock(abovePos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS | Block.UPDATE_NEIGHBORS);
+ Block.popResource(world, abovePos, new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.REDSTONE));
+ // now check that this didn't change our state
+ if (world.getBlockState(pos) != state) {
+ // our state was changed, so we cannot propagate this update
+ return;
+ }
+ }
+ }
+ // Paper end - break redstone on trapdoors early
+ if (open) { // Paper - break redstone on trapdoors early
state = (BlockState) state.setValue(TrapDoorBlock.OPEN, flag1);
this.playSound((Player) null, world, pos, flag1);
}

View file

@ -1,22 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Doc <nachito94@msn.com>
Date: Mon, 1 May 2023 13:34:57 -0400
Subject: [PATCH] Fix DamageCause for Falling Blocks
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 3362ded586f723ef1f89ad6dfa872ae468f92933..32587ddf2440cbb16884ed8140f8827357a44cba 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1058,6 +1058,11 @@ public class CraftEventFactory {
} else if (source.is(DamageTypes.SONIC_BOOM)) {
cause = DamageCause.SONIC_BOOM;
}
+ // Paper start - fix handle of Falling Blocks
+ else if (source.is(DamageTypes.FALLING_STALACTITE) || source.is(DamageTypes.FALLING_BLOCK) || source.is(DamageTypes.FALLING_ANVIL)) {
+ cause = DamageCause.FALLING_BLOCK;
+ }
+ // Paper end
return CraftEventFactory.callEntityDamageEvent(damager, entity, cause, modifiers, modifierFunctions, cancelled, source.isCritical()); // Paper - add critical damage API
} else if (source.is(DamageTypes.FELL_OUT_OF_WORLD)) {

View file

@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Sun, 14 May 2023 00:47:28 -0400
Subject: [PATCH] Avoid Lazy Initialization for Enum Fields
This patch is meant to get rid of any instances of lazy initialization that Minecraft introduces for enums.
This has the possibility to create race condition issues, and generally don't make sense to be lazily done anyways.
diff --git a/src/main/java/com/mojang/math/OctahedralGroup.java b/src/main/java/com/mojang/math/OctahedralGroup.java
index a5a889d40228a0d6c7259caf8cb2554588d9aaf9..bbd407ab618fc89a82a6724ba3503d8b4a397016 100644
--- a/src/main/java/com/mojang/math/OctahedralGroup.java
+++ b/src/main/java/com/mojang/math/OctahedralGroup.java
@@ -111,6 +111,7 @@ public enum OctahedralGroup implements StringRepresentable {
this.permutation = axisTransformation;
this.transformation = (new Matrix3f()).scaling(flipX ? -1.0F : 1.0F, flipY ? -1.0F : 1.0F, flipZ ? -1.0F : 1.0F);
this.transformation.mul(axisTransformation.transformation());
+ this.initializeRotationDirections(); // Paper
}
private BooleanList packInversions() {
@@ -139,7 +140,7 @@ public enum OctahedralGroup implements StringRepresentable {
return this.name;
}
- public Direction rotate(Direction direction) {
+ public void initializeRotationDirections() { // Paper
if (this.rotatedDirections == null) {
this.rotatedDirections = Maps.newEnumMap(Direction.class);
Direction.Axis[] axiss = Direction.Axis.values();
@@ -154,6 +155,10 @@ public enum OctahedralGroup implements StringRepresentable {
}
}
+ // Paper start - Move lazy initialization to constructor
+ }
+ public Direction rotate(Direction direction) {
+ // Paper end
return this.rotatedDirections.get(direction);
}

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Warrior <50800980+Warriorrrr@users.noreply.github.com>
Date: Sun, 7 May 2023 22:33:50 +0200
Subject: [PATCH] More accurate isInOpenWater impl
For fishing hooks, the openWater field is true by default, and only calculated when a "fish" is approaching the bobber.
This patch changes the API impl to calculate the open water state itself instead of returning this field.
Relevant link: https://github.com/PaperMC/Paper/issues/9131
== AT ==
public net.minecraft.world.entity.projectile.FishingHook calculateOpenWater(Lnet/minecraft/core/BlockPos;)Z
public net.minecraft.world.entity.projectile.FishingHook outOfWaterTime
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java
index 9de72665c947bb00547cdd7c41a890711f5b2afc..96b6e537ec4493a0cdd98ccfe7816f7ffb69c7dd 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFishHook.java
@@ -164,7 +164,7 @@ public class CraftFishHook extends CraftProjectile implements FishHook {
@Override
public boolean isInOpenWater() {
- return this.getHandle().isOpenWaterFishing();
+ return this.getHandle().outOfWaterTime < 10 && this.getHandle().calculateOpenWater(this.getHandle().blockPosition()); // Paper - isOpenWaterFishing is only calculated when a "fish" is approaching the hook
}
@Override

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 15 May 2023 00:20:59 -0700
Subject: [PATCH] Fix concurrenct access to lookups field in RegistryOps
The concurrent access occurs on the Netty IO threads when
serializing packets. Thus, it seems it was an oversight of
the implementator of this function as there are typically
more than one Netty IO thread.
Fixes https://github.com/PaperMC/Folia/issues/11
diff --git a/src/main/java/net/minecraft/resources/RegistryOps.java b/src/main/java/net/minecraft/resources/RegistryOps.java
index 7709eeac907c4895a264cec0a3d453aa8b194c18..29182c49b30110809f786ae99b47fcc67976562f 100644
--- a/src/main/java/net/minecraft/resources/RegistryOps.java
+++ b/src/main/java/net/minecraft/resources/RegistryOps.java
@@ -19,11 +19,11 @@ public class RegistryOps<T> extends DelegatingOps<T> {
private static RegistryOps.RegistryInfoLookup memoizeLookup(final RegistryOps.RegistryInfoLookup registryInfoGetter) {
return new RegistryOps.RegistryInfoLookup() {
- private final Map<ResourceKey<? extends Registry<?>>, Optional<? extends RegistryOps.RegistryInfo<?>>> lookups = new HashMap<>();
+ private final Map<ResourceKey<? extends Registry<?>>, Optional<? extends RegistryOps.RegistryInfo<?>>> lookups = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - fix concurrent access to lookups field
@Override
public <T> Optional<RegistryOps.RegistryInfo<T>> lookup(ResourceKey<? extends Registry<? extends T>> registryRef) {
- return this.lookups.computeIfAbsent(registryRef, registryInfoGetter::lookup);
+ return (Optional<RegistryOps.RegistryInfo<T>>)this.lookups.computeIfAbsent(registryRef, registryInfoGetter::lookup); // Paper - fix concurrent access to lookups field
}
};
}

View file

@ -1,37 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 15 May 2023 20:25:26 -0700
Subject: [PATCH] Optimise recalcBlockCounts() for empty sections
In 1.18, every chunk section is initialised to a non-null value
and recalcBlockCounts() is invoked for each section.
However, in a standard world, most sections are empty. In such cases,
recalcBlockCounts() would iterate over ever position - even though
the block data would all be air. To avoid this, we skip
searching the section unless the palette indicates there _could_ be
a non-air block state or non-empty fluid state.
Chunk loading initially showed that recalcBlockCounts() over
sections with a ZeroBitStorage data to to take ~20% of the process,
now it takes <1%.
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
index 7a57a75db00cd64e4c95740b575277a1f355e414..d4477b0dda6a1ef7bd8323c0d11b636bd071d18e 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -232,6 +232,7 @@ public class LevelChunkSection {
this.nonEmptyBlockCount = 0;
this.tickingBlockCount = 0;
this.tickingFluidCount = 0;
+ if (this.maybeHas((BlockState state) -> !state.isAir() || !state.getFluidState().isEmpty())) { // Paper - do not run forEachLocation on clearly empty sections
this.states.forEachLocation((BlockState iblockdata, int i) -> {
FluidState fluid = iblockdata.getFluidState();
@@ -251,6 +252,7 @@ public class LevelChunkSection {
}
});
+ } // Paper - do not run forEachLocation on clearly empty sections
// Paper end
this.initBlockCollisionData(); // Paper
}

View file

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Mon, 3 Apr 2023 21:14:19 -0700
Subject: [PATCH] Fix destroying beehive without any players nearby throwing an
exception
If the player moves out of range by the time the block is destroyed,
then the exception would throw and remove the player from the world
diff --git a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
index 01c8394c6e6b65f40db04280458d0191c116b845..8b715a750a0406d1d7b25c2f023dc2fb4d8b70fa 100644
--- a/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/BeehiveBlock.java
@@ -98,6 +98,11 @@ public class BeehiveBlock extends BaseEntityBlock {
if (!list.isEmpty()) {
List<Player> list1 = world.getEntitiesOfClass(Player.class, (new AABB(pos)).inflate(8.0D, 6.0D, 8.0D));
+ // Paper start - if there are no players nearby, then nextInt() will throw
+ if (list1.isEmpty()) {
+ return;
+ }
+ // Paper end - if there are no players nearby, then nextInt() will throw
int i = list1.size();
Iterator iterator = list.iterator();

View file

@ -1,69 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 20 Jan 2022 18:11:20 -0800
Subject: [PATCH] Expand PlayerItemMendEvent
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
index 8d8fe55a05eea237a8af99ed15ab16d6167daa77..eca634792d2a7cc649675e3394e84dbaf1453905 100644
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
@@ -337,7 +337,7 @@ public class ExperienceOrb extends Entity {
ItemStack itemstack = (ItemStack) entry.getValue();
int j = Math.min(this.xpToDurability(this.value), itemstack.getDamageValue());
// CraftBukkit start
- org.bukkit.event.player.PlayerItemMendEvent event = CraftEventFactory.callPlayerItemMendEvent(player, this, itemstack, entry.getKey(), j);
+ org.bukkit.event.player.PlayerItemMendEvent event = CraftEventFactory.callPlayerItemMendEvent(player, this, itemstack, entry.getKey(), j, this::durabilityToXp); // Paper
j = event.getRepairAmount();
if (event.isCancelled()) {
return amount;
@@ -345,8 +345,13 @@ public class ExperienceOrb extends Entity {
// CraftBukkit end
itemstack.setDamageValue(itemstack.getDamageValue() - j);
- int k = amount - this.durabilityToXp(j);
+ int k = amount - event.getDurabilityToXpOperation().applyAsInt(j); // Paper
this.value = k; // CraftBukkit - update exp value of orb for PlayerItemMendEvent calls
+ // Paper start
+ if (j == 0 && amount == k) { // if repair amount is 0 and no xp was removed, don't do recursion; treat as cancelled
+ return k;
+ }
+ // Paper end
return k > 0 ? this.repairPlayerItems(player, k) : 0;
} else {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 241cc7dda1de8c711050b269b74b1b74adef5fce..5be4d15ac3df989339c586bbeb8148b1b41d47d4 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1735,11 +1735,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
orb.setPosRaw(handle.getX(), handle.getY(), handle.getZ());
int i = Math.min(orb.xpToDurability(amount), itemstack.getDamageValue());
- org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, stackEntry.getKey(), i);
+ org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, stackEntry.getKey(), i, orb::durabilityToXp); // Paper
i = event.getRepairAmount();
orb.discard();
if (!event.isCancelled()) {
- amount -= orb.durabilityToXp(i);
+ amount -= event.getDurabilityToXpOperation().applyAsInt(i); // Paper
itemstack.setDamageValue(itemstack.getDamageValue() - i);
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 32587ddf2440cbb16884ed8140f8827357a44cba..36027749504b239285c57630c0500dfb5a6126ef 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1294,10 +1294,10 @@ public class CraftEventFactory {
return event;
}
- public static PlayerItemMendEvent callPlayerItemMendEvent(net.minecraft.world.entity.player.Player entity, net.minecraft.world.entity.ExperienceOrb orb, net.minecraft.world.item.ItemStack nmsMendedItem, net.minecraft.world.entity.EquipmentSlot slot, int repairAmount) {
+ public static PlayerItemMendEvent callPlayerItemMendEvent(net.minecraft.world.entity.player.Player entity, net.minecraft.world.entity.ExperienceOrb orb, net.minecraft.world.item.ItemStack nmsMendedItem, net.minecraft.world.entity.EquipmentSlot slot, int repairAmount, java.util.function.IntUnaryOperator durabilityToXpOp) { // Paper
Player player = (Player) entity.getBukkitEntity();
org.bukkit.inventory.ItemStack bukkitStack = CraftItemStack.asCraftMirror(nmsMendedItem);
- PlayerItemMendEvent event = new PlayerItemMendEvent(player, bukkitStack, CraftEquipmentSlot.getSlot(slot), (ExperienceOrb) orb.getBukkitEntity(), repairAmount);
+ PlayerItemMendEvent event = new PlayerItemMendEvent(player, bukkitStack, CraftEquipmentSlot.getSlot(slot), (ExperienceOrb) orb.getBukkitEntity(), repairAmount, durabilityToXpOp); // Paper
Bukkit.getPluginManager().callEvent(event);
return event;
}

View file

@ -1,85 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 30 May 2023 12:59:10 -0700
Subject: [PATCH] Refresh ProjectileSource for projectiles
Makes sure the value returned by Projectile#getShooter in
the API matches the owner UUID specified in the entity nbt.
Previously, after the entity reloaded, Projectile#getShooter
would return null, while the entity still had an owner.
Also fixes setting the shooter/owner to null actually
clearing the owner.
Co-authored-by: Warrior <50800980+Warriorrrr@users.noreply.github.com>
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index d9f6b0e0b20f4106ffead6b773b5489b71924c61..cf9393dd02565134a1ce428e84a9f26ac2d39a0d 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -382,6 +382,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
public boolean valid;
public boolean generation;
public int maxAirTicks = this.getDefaultMaxAirSupply(); // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir()
+ @Nullable // Paper
public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only
public boolean lastDamageCancelled; // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Keep track if the event was canceled
public boolean persistentInvisibility = false;
diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
index 6d7ac0c8c171834fa8da94f158258a4774d80ec4..a90317100d32974e481e14476843f66997a2cf3a 100644
--- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java
@@ -49,14 +49,31 @@ public abstract class Projectile extends Entity implements TraceableEntity {
this.ownerUUID = entity.getUUID();
this.cachedOwner = entity;
}
- this.projectileSource = (entity != null && entity.getBukkitEntity() instanceof ProjectileSource) ? (ProjectileSource) entity.getBukkitEntity() : null; // CraftBukkit
-
+ // Paper start - Fix null owners not being handled
+ else {
+ this.ownerUUID = null;
+ this.cachedOwner = null;
+ this.projectileSource = null;
+ }
+ // Paper end
+ this.refreshProjectileSource(false); // Paper
+ }
+ // Paper start
+ public void refreshProjectileSource(boolean fillCache) {
+ if (fillCache) {
+ this.getOwner();
+ }
+ if (this.cachedOwner != null && !this.cachedOwner.isRemoved() && this.projectileSource == null && this.cachedOwner.getBukkitEntity() instanceof ProjectileSource projSource) {
+ this.projectileSource = projSource;
+ }
}
+ // Paper end
@Nullable
@Override
public Entity getOwner() {
if (this.cachedOwner != null && !this.cachedOwner.isRemoved()) {
+ this.refreshProjectileSource(false); // Paper
return this.cachedOwner;
} else if (this.ownerUUID != null && this.level() instanceof ServerLevel) {
this.cachedOwner = ((ServerLevel) this.level()).getEntity(this.ownerUUID);
@@ -72,6 +89,7 @@ public abstract class Projectile extends Entity implements TraceableEntity {
}
}
// Paper end
+ this.refreshProjectileSource(false); // Paper
return this.cachedOwner;
} else {
return null;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java
index b3814bd6c6d6aae090fe417696535ed1376d84d5..5e82b2d57833fea1adb342f5c8d25f55491945cb 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java
@@ -64,6 +64,7 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti
@Override
public final org.bukkit.projectiles.ProjectileSource getShooter() {
+ this.getHandle().refreshProjectileSource(true); // Paper
return this.getHandle().projectileSource;
}

View file

@ -1,41 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Malfrador <malfrador@gmail.com>
Date: Wed, 31 May 2023 23:30:00 +0200
Subject: [PATCH] Add transient modifier API
diff --git a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java
index 12135ffeacd648f6bc4d7d327059ea1a7e8c79c4..52439f4b959c74027eb191a3af960c70beb978e8 100644
--- a/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java
+++ b/src/main/java/io/papermc/paper/attribute/UnmodifiableAttributeInstance.java
@@ -23,6 +23,11 @@ public class UnmodifiableAttributeInstance extends CraftAttributeInstance {
throw new UnsupportedOperationException("Cannot modify default attributes");
}
+ @Override
+ public void addTransientModifier(AttributeModifier modifier) {
+ throw new UnsupportedOperationException("Cannot modify default attributes");
+ }
+
@Override
public void removeModifier(AttributeModifier modifier) {
throw new UnsupportedOperationException("Cannot modify default attributes");
diff --git a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java
index e828ef7df04de98628e59e93c0431ea0e10199f8..0029412b1242879deb898524001bb4cc7550fa78 100644
--- a/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java
+++ b/src/main/java/org/bukkit/craftbukkit/attribute/CraftAttributeInstance.java
@@ -50,6 +50,14 @@ public class CraftAttributeInstance implements AttributeInstance {
this.handle.addPermanentModifier(CraftAttributeInstance.convert(modifier));
}
+ // Paper start - Transient modifier API
+ @Override
+ public void addTransientModifier(AttributeModifier modifier) {
+ Preconditions.checkArgument(modifier != null, "modifier");
+ this.handle.addTransientModifier(CraftAttributeInstance.convert(modifier));
+ }
+ // Paper end
+
@Override
public void removeModifier(AttributeModifier modifier) {
Preconditions.checkArgument(modifier != null, "modifier");

View file

@ -1,68 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Date: Mon, 3 Apr 2023 18:46:49 +0200
Subject: [PATCH] Fix block place logic
Fix several issues when a player interact with a block:
* the place sound isn't played for the dispensed shulker block
* desync of the jukebox blocks between bukkit handler and the vanilla interaction
* poi can desync when the BlockPhysicsEvent is cancelled
diff --git a/src/main/java/net/minecraft/world/item/BlockItem.java b/src/main/java/net/minecraft/world/item/BlockItem.java
index b0204af850ee182773ad458208cccd946ad148d5..ebee8de2ed831755b6fd154f6cc77ac993839bb9 100644
--- a/src/main/java/net/minecraft/world/item/BlockItem.java
+++ b/src/main/java/net/minecraft/world/item/BlockItem.java
@@ -131,7 +131,7 @@ public class BlockItem extends Item {
SoundType soundeffecttype = iblockdata1.getSoundType();
- // world.playSound(entityhuman, blockposition, this.getPlaceSound(iblockdata1), SoundCategory.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F);
+ if (entityhuman == null) world.playSound(entityhuman, blockposition, this.getPlaceSound(iblockdata1), net.minecraft.sounds.SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F); // Paper - reintroduce this for the dispenser (i.e the shulker)
world.gameEvent(GameEvent.BLOCK_PLACE, blockposition, GameEvent.Context.of(entityhuman, iblockdata1));
if ((entityhuman == null || !entityhuman.getAbilities().instabuild) && itemstack != ItemStack.EMPTY) { // CraftBukkit
itemstack.shrink(1);
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index c9363f01b3c2369d5c63e50977c28a3fa760bae1..6f00794aec16db3e7a466f4b446d38bdb2623e8b 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -467,13 +467,7 @@ public final class ItemStack {
if (tileentity instanceof JukeboxBlockEntity) {
JukeboxBlockEntity tileentityjukebox = (JukeboxBlockEntity) tileentity;
- // There can only be one
- ItemStack record = this.copy();
- if (!record.isEmpty()) {
- record.setCount(1);
- }
-
- tileentityjukebox.setFirstItem(record);
+ tileentityjukebox.setFirstItem(this.copy()); // Paper - sync this with record item, jukebox has now an inventory
world.gameEvent(GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entityhuman, world.getBlockState(blockposition)));
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index c24944d24d6e40e853823e6e2653275553157b1f..773bfdd3ed457a352b5329f280c0d10297d579ba 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -730,17 +730,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// CraftBukkit start
iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam
CraftWorld world = ((ServerLevel) this).getWorld();
+ boolean cancelledUpdates = false; // Paper
if (world != null && ((ServerLevel)this).hasPhysicsEvent) { // Paper
BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata));
this.getCraftServer().getPluginManager().callEvent(event);
- if (event.isCancelled()) {
- return;
- }
+ cancelledUpdates = event.isCancelled(); // Paper
}
// CraftBukkit end
+ if (!cancelledUpdates) { // Paper
iblockdata.updateNeighbourShapes(this, blockposition, k, j - 1);
iblockdata.updateIndirectNeighbourShapes(this, blockposition, k, j - 1);
+ } // Paper
}
// CraftBukkit start - SPIGOT-5710

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Thu, 8 Jun 2023 20:23:13 -0400
Subject: [PATCH] Fix spigot sound playing for BlockItem ItemStacks
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 6f00794aec16db3e7a466f4b446d38bdb2623e8b..2223aba0841280c5205ab0963c406449f85fa433 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -518,7 +518,11 @@ public final class ItemStack {
// SPIGOT-1288 - play sound stripped from ItemBlock
if (this.item instanceof BlockItem) {
- SoundType soundeffecttype = ((BlockItem) this.item).getBlock().defaultBlockState().getSoundType(); // TODO: not strictly correct, however currently only affects decorated pots
+ // Paper start
+ BlockPos position = new net.minecraft.world.item.context.BlockPlaceContext(context).getClickedPos();
+ net.minecraft.world.level.block.state.BlockState blockData = world.getBlockState(position);
+ SoundType soundeffecttype = blockData.getSoundType();
+ // Paper end
world.playSound(entityhuman, blockposition, soundeffecttype.getPlaceSound(), SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F);
}

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Thu, 8 Jun 2023 21:51:50 -0700
Subject: [PATCH] Ignore inline definitions of trim material & pattern
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java
index 742d4039392403a75882f83bb2f64453898adf76..c92981aedebe934cefa1c96a0328fb91fe17acbc 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmor.java
@@ -67,7 +67,7 @@ public class CraftMetaArmor extends CraftMetaItem implements ArmorMeta {
if (tag.contains(TRIM.NBT)) {
CompoundTag trimCompound = tag.getCompound(TRIM.NBT);
- if (trimCompound.contains(TRIM_MATERIAL.NBT) && trimCompound.contains(TRIM_PATTERN.NBT)) {
+ if (trimCompound.contains(TRIM_MATERIAL.NBT, net.minecraft.nbt.Tag.TAG_STRING) && trimCompound.contains(TRIM_PATTERN.NBT, net.minecraft.nbt.Tag.TAG_STRING)) { // Paper - for now, ignore inline definitions of trim material & pattern
TrimMaterial trimMaterial = Registry.TRIM_MATERIAL.get(NamespacedKey.fromString(trimCompound.getString(TRIM_MATERIAL.NBT)));
TrimPattern trimPattern = Registry.TRIM_PATTERN.get(NamespacedKey.fromString(trimCompound.getString(TRIM_PATTERN.NBT)));

View file

@ -1,39 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Date: Fri, 9 Jun 2023 13:04:42 +0200
Subject: [PATCH] Call BlockGrowEvent for missing blocks
Call the event for pitcher crops and sniffer egg
diff --git a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java
index 849c0ae6ca30691134f51e5d4d5da372e0e728bd..d2e8aafb8db17f2426dd83353c0cfdeaf0d372aa 100644
--- a/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/PitcherCropBlock.java
@@ -126,7 +126,7 @@ public class PitcherCropBlock extends DoublePlantBlock implements BonemealableBl
private void grow(ServerLevel world, BlockState state, BlockPos pos, int amount) {
int i = Math.min(state.getValue(AGE) + amount, 4);
if (this.canGrow(world, pos, state, i)) {
- world.setBlock(pos, state.setValue(AGE, Integer.valueOf(i)), 2);
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, state.setValue(AGE, Integer.valueOf(i)), 2)) return; // Paper
if (i >= 3) {
BlockPos blockPos = pos.above();
world.setBlock(blockPos, copyWaterloggedFrom(world, pos, this.defaultBlockState().setValue(AGE, Integer.valueOf(i)).setValue(HALF, DoubleBlockHalf.UPPER)), 3);
diff --git a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java
index ecb8224beb0ee65855c7529b69ea56b7b6674664..fab44502b3e22eb8d1311068f88290ce31adb437 100644
--- a/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SnifferEggBlock.java
@@ -65,8 +65,13 @@ public class SnifferEggBlock extends Block {
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
if (!this.isReadyToHatch(state)) {
+ // Paper start
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, state.setValue(HATCH, Integer.valueOf(this.getHatchLevel(state) + 1)), 2)) {
+ rescheduleTick(world, pos);
+ return;
+ }
+ // Paper end
world.playSound((Player)null, pos, SoundEvents.SNIFFER_EGG_CRACK, SoundSource.BLOCKS, 0.7F, 0.9F + random.nextFloat() * 0.2F);
- world.setBlock(pos, state.setValue(HATCH, Integer.valueOf(this.getHatchLevel(state) + 1)), 2);
} else {
// Paper start - Call BlockFadeEvent
if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFadeEvent(world, pos, state.getFluidState().createLegacyBlock()).isCancelled()) {

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: TheMeinerLP <p.glanz@madfix.me>
Date: Tue, 13 Jun 2023 16:10:59 +0200
Subject: [PATCH] Don't enforce icanhasbukkit default if alias block exists
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 03fcdb0eb145d60b96bf241523ade1f4595abdef..1d62b3fa7cfbb891b7a1fda01a22f64a6bc1968e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -357,7 +357,11 @@ public final class CraftServer implements Server {
}
this.commandsConfiguration = YamlConfiguration.loadConfiguration(this.getCommandsConfigFile());
this.commandsConfiguration.options().copyDefaults(true);
- this.commandsConfiguration.setDefaults(YamlConfiguration.loadConfiguration(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("configurations/commands.yml"), Charsets.UTF_8)));
+ // Paper start - don't enforce icanhasbukkit default if alias block exists
+ final YamlConfiguration commandsDefaults = YamlConfiguration.loadConfiguration(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("configurations/commands.yml"), Charsets.UTF_8));
+ if (this.commandsConfiguration.contains("aliases")) commandsDefaults.set("aliases", null);
+ this.commandsConfiguration.setDefaults(commandsDefaults);
+ // Paper stop - dont enforce icanhasbukkit default if alias block exists
this.saveCommandsConfig();
// Migrate aliases from old file and add previously implicit $1- to pass all arguments

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Wed, 14 Jun 2023 13:17:40 -0700
Subject: [PATCH] fix MapLike spam for missing key 'selector'
diff --git a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java
index 1fe9af20ca9b17cf346e28fc2075ce1db00d5dcd..043edba56c3d0021b9cdfafd9588ec6a50f944ab 100644
--- a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java
+++ b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationSystem.java
@@ -350,7 +350,7 @@ public interface VibrationSystem {
public static Codec<VibrationSystem.Data> CODEC = RecordCodecBuilder.create((instance) -> {
return instance.group(VibrationInfo.CODEC.optionalFieldOf("event").forGetter((vibrationsystem_a) -> {
return Optional.ofNullable(vibrationsystem_a.currentVibration);
- }), VibrationSelector.CODEC.fieldOf("selector").forGetter(VibrationSystem.Data::getSelectionStrategy), ExtraCodecs.NON_NEGATIVE_INT.fieldOf("event_delay").orElse(0).forGetter(VibrationSystem.Data::getTravelTimeInTicks)).apply(instance, (optional, vibrationselector, integer) -> {
+ }), Codec.optionalField("selector", VibrationSelector.CODEC).xmap(o -> o.orElseGet(VibrationSelector::new), Optional::of).forGetter(VibrationSystem.Data::getSelectionStrategy), ExtraCodecs.NON_NEGATIVE_INT.fieldOf("event_delay").orElse(0).forGetter(VibrationSystem.Data::getTravelTimeInTicks)).apply(instance, (optional, vibrationselector, integer) -> { // Paper - fix MapLike spam for missing "selector" in 1.19.2
return new VibrationSystem.Data((VibrationInfo) optional.orElse(null), vibrationselector, integer, true); // CraftBukkit - decompile error
});
});

View file

@ -1,29 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Date: Sun, 11 Jun 2023 19:02:46 +0200
Subject: [PATCH] Fix sniffer removeExploredLocation
Add support to remove explored location in different world
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java
index 1c8b67de03aefe91bf80782fb14fb629a458ecc3..01328768ef2baba2aa7fea7e10b0eb9783497f4b 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSniffer.java
@@ -34,12 +34,13 @@ public class CraftSniffer extends CraftAnimals implements Sniffer {
@Override
public void removeExploredLocation(Location location) {
Preconditions.checkArgument(location != null, "location cannot be null");
- if (location.getWorld() != getWorld()) {
- return;
- }
BlockPos blockPosition = CraftLocation.toBlockPosition(location);
- this.getHandle().getBrain().setMemory(MemoryModuleType.SNIFFER_EXPLORED_POSITIONS, this.getHandle().getExploredPositions().filter(blockPositionExplored -> !blockPositionExplored.equals(blockPosition)).collect(Collectors.toList()));
+ // Paper start
+ net.minecraft.world.level.Level level = location.getWorld() != null ? ((org.bukkit.craftbukkit.CraftWorld) location.getWorld()).getHandle() : this.getHandle().level();
+ net.minecraft.core.GlobalPos globalPos = net.minecraft.core.GlobalPos.of(level.dimension(), blockPosition);
+ this.getHandle().getBrain().setMemory(MemoryModuleType.SNIFFER_EXPLORED_POSITIONS, this.getHandle().getExploredPositions().filter(blockPositionExplored -> !blockPositionExplored.equals(globalPos)).collect(Collectors.toList()));
+ // Paper end
}
@Override

View file

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 17 Jun 2023 13:17:25 -0700
Subject: [PATCH] Add method to remove all active potion effects
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index ae1a86798a5d65ec6ee4388c650e09850c3f35f8..b25f5931f836fd4d8695120f0bcb7c52deff8583 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -503,6 +503,13 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
return effects;
}
+ // Paper start - LivingEntity#clearActivePotionEffects();
+ @Override
+ public boolean clearActivePotionEffects() {
+ return this.getHandle().removeAllEffects(EntityPotionEffectEvent.Cause.PLUGIN);
+ }
+ // Paper end
+
@Override
public <T extends Projectile> T launchProjectile(Class<? extends T> projectile) {
return this.launchProjectile(projectile, null);

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sun, 18 Jun 2023 13:48:11 +0100
Subject: [PATCH] Temp: Pre-init PlayerChunkLoaderData in order to prepopulate
the BFS lookup cache because potatos
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 2b27feda982ca55257b55c801ec772a18157bd01..7c29d92362a82330440dff151bcf421f15c68f71 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -367,6 +367,7 @@ public class Main {
tryPreloadClass(net.minecraft.world.level.lighting.LayerLightEventListener.DummyLightLayerEventListener.class.getName());
tryPreloadClass(net.minecraft.world.level.lighting.LayerLightEventListener.class.getName());
tryPreloadClass(net.minecraft.util.ExceptionCollector.class.getName());
+ tryPreloadClass(io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.PlayerChunkLoaderData.class.getName());
// Paper end
}
}

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Redned <redned235@gmail.com>
Date: Mon, 12 Jun 2023 11:54:12 -0500
Subject: [PATCH] Fix incorrect crafting result amount for fireworks
Although vanilla does not specifically call this method anywhere, this fixes a bug where the result using the Bukkit API returns the wrong amount.
diff --git a/src/main/java/net/minecraft/world/item/crafting/FireworkRocketRecipe.java b/src/main/java/net/minecraft/world/item/crafting/FireworkRocketRecipe.java
index 5296f47a7e344ac59664a48e8ce91240393c7e12..b611ce69defe0dfa69c43f138b20d107c3f46c05 100644
--- a/src/main/java/net/minecraft/world/item/crafting/FireworkRocketRecipe.java
+++ b/src/main/java/net/minecraft/world/item/crafting/FireworkRocketRecipe.java
@@ -82,7 +82,7 @@ public class FireworkRocketRecipe extends CustomRecipe {
@Override
public ItemStack getResultItem(RegistryAccess registryManager) {
- return new ItemStack(Items.FIREWORK_ROCKET);
+ return new ItemStack(Items.FIREWORK_ROCKET, 3); // Paper - Fix incorrect crafting result amount
}
@Override

View file

@ -1,64 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
Date: Tue, 23 May 2023 22:33:36 -0400
Subject: [PATCH] Properly Cancel Usable Items
This fixes the bug causing cancelling PlayerInteractEvent to cause items to continue to be used despite being cancelled on the server.
For example, items being consumed but never finishing, shields being put up, etc.
The underlying issue of this is that the client modifies their synced data values, and so we have to (forcibly) resend
them in order for the client to reset their using item state.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index 34ecfb89372f459117db99d57a7edd6f681bbe8a..baf3e79489e310f443788bc917c553ae7ea86c89 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -562,6 +562,7 @@ public class ServerPlayerGameMode {
}
// Paper end - extend Player Interact cancellation
player.getBukkitEntity().updateInventory(); // SPIGOT-2867
+ this.player.resyncUsingItem(this.player); // Paper - Resend player's using item status
enuminteractionresult = (event.useItemInHand() != Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
} else if (this.gameModeForPlayer == GameType.SPECTATOR) {
MenuProvider itileinventory = iblockdata.getMenuProvider(world, blockposition);
@@ -605,6 +606,11 @@ public class ServerPlayerGameMode {
return enuminteractionresult1;
}
+ // Paper start - Cancel only if cancelled + if the interact result is different from default response
+ else if (this.interactResult && this.interactResult != cancelledItem) {
+ this.player.resyncUsingItem(this.player);
+ }
+ // Paper end
}
return enuminteractionresult;
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index f6ba77a7c43a6a030fe4073ba7ee2970e7d774f3..c80aaaea583f87143dab2a4d314b8b3f83d8bbf6 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2031,6 +2031,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
}
if (cancelled) {
+ this.player.resyncUsingItem(this.player); // Paper - Resend player's using item status
this.player.getBukkitEntity().updateInventory(); // SPIGOT-2524
return;
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index cf3173c3b3d3362040eb57ee39221e24a5bc5221..78c98f38bc263664ea4cd344670243a7d372885c 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3748,6 +3748,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
}
+ // Paper start
+ public void resyncUsingItem(ServerPlayer serverPlayer) {
+ this.getEntityData().resendPossiblyDesyncedDataValues(java.util.List.of(DATA_LIVING_ENTITY_FLAGS), serverPlayer);
+ }
+ // Paper end
+
// Paper start - lag compensate eating
protected long eatStartTime;
protected int totalEatTimeTicks;

View file

@ -1,92 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: by77er <by77er@gmail.com>
Date: Mon, 12 Jun 2023 12:56:46 -0400
Subject: [PATCH] Add event for player editing sign
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
index 2223aba0841280c5205ab0963c406449f85fa433..879cc823d56625867eb73bb621db6a13f40ad81c 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
@@ -497,7 +497,7 @@ public final class ItemStack {
try {
if (world.getBlockEntity(SignItem.openSign) instanceof SignBlockEntity tileentitysign) {
if (world.getBlockState(SignItem.openSign).getBlock() instanceof SignBlock blocksign) {
- blocksign.openTextEdit(entityhuman, tileentitysign, true, org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLACE); // Craftbukkit
+ blocksign.openTextEdit(entityhuman, tileentitysign, true, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLACE); // Paper
}
}
} finally {
diff --git a/src/main/java/net/minecraft/world/level/block/SignBlock.java b/src/main/java/net/minecraft/world/level/block/SignBlock.java
index 1733744691e843891fc22991f8da57877a1b14f3..b01cdfe3c62c609e953aa5007e6557cfec0d5a5f 100644
--- a/src/main/java/net/minecraft/world/level/block/SignBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/SignBlock.java
@@ -115,7 +115,7 @@ public abstract class SignBlock extends BaseEntityBlock implements SimpleWaterlo
} else if (flag2) {
return InteractionResult.SUCCESS;
} else if (!this.otherPlayerIsEditingSign(player, tileentitysign) && player.mayBuild() && this.hasEditableText(player, tileentitysign, flag1)) {
- this.openTextEdit(player, tileentitysign, flag1, org.bukkit.event.player.PlayerSignOpenEvent.Cause.INTERACT); // CraftBukkit
+ this.openTextEdit(player, tileentitysign, flag1, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.INTERACT); // Paper
return InteractionResult.SUCCESS;
} else {
return InteractionResult.PASS;
@@ -163,16 +163,33 @@ public abstract class SignBlock extends BaseEntityBlock implements SimpleWaterlo
return blockpropertywood;
}
+ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper
public void openTextEdit(Player player, SignBlockEntity blockEntity, boolean front) {
- // Craftbukkit start
- this.openTextEdit(player, blockEntity, front, org.bukkit.event.player.PlayerSignOpenEvent.Cause.UNKNOWN);
+ // Paper start - PlayerOpenSignEvent
+ this.openTextEdit(player, blockEntity, front, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.UNKNOWN);
}
-
- public void openTextEdit(Player entityhuman, SignBlockEntity tileentitysign, boolean flag, org.bukkit.event.player.PlayerSignOpenEvent.Cause cause) {
- if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerSignOpenEvent(entityhuman, tileentitysign, flag, cause)) {
+ public void openTextEdit(Player entityhuman, SignBlockEntity tileentitysign, boolean flag, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause cause) {
+ org.bukkit.entity.Player bukkitPlayer = (org.bukkit.entity.Player) entityhuman.getBukkitEntity();
+ org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(tileentitysign.getLevel(), tileentitysign.getBlockPos());
+ org.bukkit.craftbukkit.block.CraftSign<?> bukkitSign = (org.bukkit.craftbukkit.block.CraftSign<?>) org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(bukkitBlock);
+ io.papermc.paper.event.player.PlayerOpenSignEvent event = new io.papermc.paper.event.player.PlayerOpenSignEvent(
+ bukkitPlayer,
+ bukkitSign,
+ flag ? org.bukkit.block.sign.Side.FRONT : org.bukkit.block.sign.Side.BACK,
+ cause);
+ if (!event.callEvent()) return;
+ if (org.bukkit.event.player.PlayerSignOpenEvent.getHandlerList().getRegisteredListeners().length > 0) {
+ final org.bukkit.event.player.PlayerSignOpenEvent.Cause legacyCause = switch (cause) {
+ case PLACE -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLACE;
+ case PLUGIN -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLUGIN;
+ case INTERACT -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.INTERACT;
+ case UNKNOWN -> org.bukkit.event.player.PlayerSignOpenEvent.Cause.UNKNOWN;
+ };
+ // Paper end - PlayerOpenSignEvent
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerSignOpenEvent(entityhuman, tileentitysign, flag, legacyCause)) { // Paper
return;
}
- // Craftbukkit end
+ } // Paper
tileentitysign.setAllowedPlayerEditor(entityhuman.getUUID());
entityhuman.openTextEdit(tileentitysign, flag);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
index 5af30bff1bfdf09daa585071f2ec1fe04db3609f..6d40e8a75126eff3f863ab6fbea8a85ab43ac9c9 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
@@ -128,9 +128,15 @@ public class CraftSign<T extends SignBlockEntity> extends CraftBlockEntityState<
Preconditions.checkArgument(sign.isPlaced(), "Sign must be placed");
Preconditions.checkArgument(sign.getWorld() == player.getWorld(), "Sign must be in same world as Player");
+ // Paper start
+ io.papermc.paper.event.player.PlayerOpenSignEvent event = new io.papermc.paper.event.player.PlayerOpenSignEvent((Player) player, sign, side, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLUGIN);
+ if (!event.callEvent()) return;
+ if (PlayerSignOpenEvent.getHandlerList().getRegisteredListeners().length > 0) {
+ // Paper end
if (!CraftEventFactory.callPlayerSignOpenEvent(player, sign, side, PlayerSignOpenEvent.Cause.PLUGIN)) {
return;
}
+ } // Paper
SignBlockEntity handle = ((CraftSign<?>) sign).getTileEntity();
handle.setAllowedPlayerEditor(player.getUniqueId());

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Redned <redned235@gmail.com>
Date: Mon, 19 Jun 2023 15:45:53 -0500
Subject: [PATCH] Only tick item frames if players can see it
In the event that an item frame cannot be seen by any players, ticking the item frame every tick is unnecessary. This can be a very hot section of the entity tracker when lots of item frames are present on a server, so this reduces the logic which speeds it up.
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index fe7aff356a9e7b4f41c3d5cb3bd5afbb0646c16a..d934d07ad761319f338d4386536f68fde211c041 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -108,7 +108,7 @@ public class ServerEntity {
Entity entity = this.entity;
- if (entity instanceof ItemFrame) {
+ if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame) { // Paper - Only tick item frames if players can see it
ItemFrame entityitemframe = (ItemFrame) entity;
if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 27 Jun 2023 16:32:39 -0700
Subject: [PATCH] Improve command function perm level checks
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
index 43c71d9bf2eac98023057b4483fdd143a8343e98..0de2eae2d448ac9e269a4edf48406d5ea8af8059 100644
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
@@ -216,8 +216,14 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy
// CraftBukkit start
public boolean hasPermission(int i, String bukkitPermission) {
- // World is null when loading functions
- return ((this.getLevel() == null || !this.getLevel().getCraftServer().ignoreVanillaPermissions) && this.permissionLevel >= i) || this.getBukkitSender().hasPermission(bukkitPermission);
+ // Paper start
+ boolean hasPermissionLevel = this.permissionLevel >= i;
+ if (this.source == CommandSource.NULL) {
+ return hasPermissionLevel;
+ } else {
+ return (!this.getLevel().getCraftServer().ignoreVanillaPermissions && hasPermissionLevel) || this.getBukkitSender().hasPermission(bukkitPermission);
+ }
+ // Paper end
}
// CraftBukkit end

View file

@ -1,175 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Boy <sivertpaulsen2@gmail.com>
Date: Sun, 18 Jun 2023 17:45:33 +0200
Subject: [PATCH] Add option to disable block updates
diff --git a/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java b/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java
index a6c25647fb37f59307de0d390f8e8cf55504d7d3..2e8bf4463b8da8da50cd14d3f84aba5e930e5710 100644
--- a/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/ChorusPlantBlock.java
@@ -21,6 +21,7 @@ public class ChorusPlantBlock extends PipeBlock {
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return this.defaultBlockState(); // Paper - add option to disable block updates
return this.getStateForPlacement(ctx.getLevel(), ctx.getClickedPos());
}
@@ -36,6 +37,7 @@ public class ChorusPlantBlock extends PipeBlock {
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return state; // Paper - add option to disable block updates
if (!state.canSurvive(world, pos)) {
world.scheduleTick(pos, this, 1);
return super.updateShape(state, direction, neighborState, world, pos, neighborPos);
@@ -47,6 +49,7 @@ public class ChorusPlantBlock extends PipeBlock {
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return; // Paper - add option to disable block updates
if (!state.canSurvive(world, pos)) {
world.destroyBlock(pos, true);
}
@@ -55,6 +58,7 @@ public class ChorusPlantBlock extends PipeBlock {
@Override
public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableChorusPlantUpdates) return true; // Paper - add option to disable block updates
BlockState blockState = world.getBlockState(pos.below());
boolean bl = !world.getBlockState(pos.above()).isAir() && !blockState.isAir();
diff --git a/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java b/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java
index 3c6d97b51c6fec130b80e5965afa2c49d48843c9..1dd44eb0ab977093660e8fe6f49338e7f5ef7b28 100644
--- a/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/HugeMushroomBlock.java
@@ -27,6 +27,7 @@ public class HugeMushroomBlock extends Block {
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return this.defaultBlockState(); // Paper - add option to disable block updates
BlockGetter blockGetter = ctx.getLevel();
BlockPos blockPos = ctx.getClickedPos();
return this.defaultBlockState().setValue(DOWN, Boolean.valueOf(!blockGetter.getBlockState(blockPos.below()).is(this))).setValue(UP, Boolean.valueOf(!blockGetter.getBlockState(blockPos.above()).is(this))).setValue(NORTH, Boolean.valueOf(!blockGetter.getBlockState(blockPos.north()).is(this))).setValue(EAST, Boolean.valueOf(!blockGetter.getBlockState(blockPos.east()).is(this))).setValue(SOUTH, Boolean.valueOf(!blockGetter.getBlockState(blockPos.south()).is(this))).setValue(WEST, Boolean.valueOf(!blockGetter.getBlockState(blockPos.west()).is(this)));
@@ -34,16 +35,19 @@ public class HugeMushroomBlock extends Block {
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates
return neighborState.is(this) ? state.setValue(PROPERTY_BY_DIRECTION.get(direction), Boolean.valueOf(false)) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
}
@Override
public BlockState rotate(BlockState state, Rotation rotation) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates
return state.setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.NORTH)), state.getValue(NORTH)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.SOUTH)), state.getValue(SOUTH)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.EAST)), state.getValue(EAST)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.WEST)), state.getValue(WEST)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.UP)), state.getValue(UP)).setValue(PROPERTY_BY_DIRECTION.get(rotation.rotate(Direction.DOWN)), state.getValue(DOWN));
}
@Override
public BlockState mirror(BlockState state, Mirror mirror) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableMushroomBlockUpdates) return state; // Paper - add option to disable block updates
return state.setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.NORTH)), state.getValue(NORTH)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.SOUTH)), state.getValue(SOUTH)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.EAST)), state.getValue(EAST)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.WEST)), state.getValue(WEST)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.UP)), state.getValue(UP)).setValue(PROPERTY_BY_DIRECTION.get(mirror.mirror(Direction.DOWN)), state.getValue(DOWN));
}
diff --git a/src/main/java/net/minecraft/world/level/block/NoteBlock.java b/src/main/java/net/minecraft/world/level/block/NoteBlock.java
index 910864cfeac085648e6c671b0f9480417324d36e..e46d84750bdd7c940f400efda226e12a3fdc3848 100644
--- a/src/main/java/net/minecraft/world/level/block/NoteBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/NoteBlock.java
@@ -58,11 +58,13 @@ public class NoteBlock extends Block {
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return this.defaultBlockState(); // Paper - place without considering instrument
return this.setInstrument(ctx.getLevel(), ctx.getClickedPos(), this.defaultBlockState());
}
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return state; // Paper - prevent noteblock instrument from updating
boolean flag = direction.getAxis() == Direction.Axis.Y;
return flag ? this.setInstrument(world, pos, state) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
@@ -70,6 +72,7 @@ public class NoteBlock extends Block {
@Override
public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) return; // Paper - prevent noteblock powered-state from updating
boolean flag1 = world.hasNeighborSignal(pos);
if (flag1 != (Boolean) state.getValue(NoteBlock.POWERED)) {
@@ -107,7 +110,7 @@ public class NoteBlock extends Block {
} else if (world.isClientSide) {
return InteractionResult.SUCCESS;
} else {
- state = (BlockState) state.cycle(NoteBlock.NOTE);
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableNoteblockUpdates) state = (BlockState) state.cycle(NoteBlock.NOTE); // Paper - prevent noteblock note from updating
world.setBlock(pos, state, 3);
this.playNote(player, state, world, pos);
player.awardStat(Stats.TUNE_NOTEBLOCK);
diff --git a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
index 7f60175bf671d282c11e9084670d2bb900968255..cb2ff8d94308c637a498d2737f86f6af4c9c1b83 100644
--- a/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/TripWireBlock.java
@@ -53,6 +53,7 @@ public class TripWireBlock extends Block {
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return this.defaultBlockState(); // Paper - place tripwire without updating
Level world = ctx.getLevel();
BlockPos blockposition = ctx.getClickedPos();
@@ -61,11 +62,13 @@ public class TripWireBlock extends Block {
@Override
public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor world, BlockPos pos, BlockPos neighborPos) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return state; // Paper - prevent tripwire from updating
return direction.getAxis().isHorizontal() ? (BlockState) state.setValue((Property) TripWireBlock.PROPERTY_BY_DIRECTION.get(direction), this.shouldConnectTo(neighborState, direction)) : super.updateShape(state, direction, neighborState, world, pos, neighborPos);
}
@Override
public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating
if (!oldState.is(state.getBlock())) {
this.updateSource(world, pos, state);
}
@@ -73,6 +76,7 @@ public class TripWireBlock extends Block {
@Override
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating
if (!moved && !state.is(newState.getBlock())) {
this.updateSource(world, pos, (BlockState) state.setValue(TripWireBlock.POWERED, true), true); // Paper - fix state inconsistency
}
@@ -80,6 +84,7 @@ public class TripWireBlock extends Block {
@Override
public void playerWillDestroy(Level world, BlockPos pos, BlockState state, Player player) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent disarming tripwires
if (!world.isClientSide && !player.getMainHandItem().isEmpty() && player.getMainHandItem().is(Items.SHEARS)) {
world.setBlock(pos, (BlockState) state.setValue(TripWireBlock.DISARMED, true), 4);
world.gameEvent((Entity) player, GameEvent.SHEAR, pos);
@@ -89,6 +94,7 @@ public class TripWireBlock extends Block {
}
private void updateSource(Level world, BlockPos pos, BlockState state) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent adjacent tripwires from updating
// Paper start - fix state inconsistency
this.updateSource(world, pos, state, false);
}
@@ -127,6 +133,7 @@ public class TripWireBlock extends Block {
@Override
public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent tripwires from detecting collision
if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(world, pos)).callEvent()) { return; } // Paper
if (!world.isClientSide) {
if (!(Boolean) state.getValue(TripWireBlock.POWERED)) {
@@ -137,6 +144,7 @@ public class TripWireBlock extends Block {
@Override
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ if (io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates) return; // Paper - prevent tripwire pressed check
if ((Boolean) world.getBlockState(pos).getValue(TripWireBlock.POWERED)) {
this.checkPressed(world, pos);
}

View file

@ -1,88 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
Date: Sat, 29 Oct 2022 15:41:56 +0200
Subject: [PATCH] Call missing BlockDispenseEvent
diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
index b4f5dbe9022dd20437c15c4f6fbe2ac06dacbadb..70aade6a8d36f8376cc567800258ea6fabb0607f 100644
--- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -1105,6 +1105,13 @@ public interface DispenseItemBehavior {
this.setSuccess(true);
if (iblockdata.is(Blocks.RESPAWN_ANCHOR)) {
if ((Integer) iblockdata.getValue(RespawnAnchorBlock.CHARGE) != 4) {
+ // Paper start
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition, stack, this);
+ if (result != null) {
+ this.setSuccess(false);
+ return result;
+ }
+ // Paper end
RespawnAnchorBlock.charge((Entity) null, worldserver, blockposition, iblockdata);
stack.shrink(1);
} else {
@@ -1127,6 +1134,13 @@ public interface DispenseItemBehavior {
Optional<BlockState> optional = HoneycombItem.getWaxed(iblockdata);
if (optional.isPresent()) {
+ // Paper start
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition, stack, this);
+ if (result != null) {
+ this.setSuccess(false);
+ return result;
+ }
+ // Paper end
worldserver.setBlockAndUpdate(blockposition, (BlockState) optional.get());
worldserver.levelEvent(3003, blockposition, 0);
stack.shrink(1);
@@ -1152,6 +1166,12 @@ public interface DispenseItemBehavior {
if (!worldserver.getBlockState(blockposition1).is(BlockTags.CONVERTABLE_TO_MUD)) {
return this.defaultDispenseItemBehavior.dispense(pointer, stack);
} else {
+ // Paper start
+ ItemStack result = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDispenseEvent(pointer, blockposition1, stack, this);
+ if (result != null) {
+ return result;
+ }
+ // Paper end
if (!worldserver.isClientSide) {
for (int k = 0; k < 5; ++k) {
worldserver.sendParticles(ParticleTypes.SPLASH, (double) blockposition.getX() + worldserver.random.nextDouble(), (double) (blockposition.getY() + 1), (double) blockposition.getZ() + worldserver.random.nextDouble(), 1, 0.0D, 0.0D, 0.0D, 1.0D);
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 36027749504b239285c57630c0500dfb5a6126ef..c514795dee0c54ae4fc1592dab5b69c39631c9ad 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -2053,6 +2053,32 @@ public class CraftEventFactory {
}
// Paper end
+ // Paper start - missing BlockDispenseEvent calls
+ @Nullable
+ public static ItemStack handleBlockDispenseEvent(net.minecraft.core.BlockSource pointer, BlockPos to, ItemStack itemStack, net.minecraft.core.dispenser.DispenseItemBehavior instance) {
+ org.bukkit.block.Block bukkitBlock = pointer.getLevel().getWorld().getBlockAt(pointer.getPos().getX(), pointer.getPos().getY(), pointer.getPos().getZ());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1));
+
+ org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(to.getX(), to.getY(), to.getZ()));
+ if (!net.minecraft.world.level.block.DispenserBlock.eventFired) {
+ if (!event.callEvent()) {
+ return itemStack;
+ }
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ net.minecraft.core.dispenser.DispenseItemBehavior idispensebehavior = net.minecraft.world.level.block.DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != net.minecraft.core.dispenser.DispenseItemBehavior.NOOP && idispensebehavior != instance) {
+ idispensebehavior.dispense(pointer, eventStack);
+ return itemStack;
+ }
+ }
+ return null;
+ }
+ // Paper end - missing BlockDispenseEvent calls
+
// Paper start - add EntityFertilizeEggEvent
/**
* Calls the io.papermc.paper.event.entity.EntityFertilizeEggEvent.

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Wed, 5 Jul 2023 23:11:53 +0100
Subject: [PATCH] Don't load chunks for supporting block checks
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index e19010627a030753b08aa8451363c6bc4631bf72..0ed297f189e5d21c497ac78294db6ca664c0f2c4 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -1368,7 +1368,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
}
protected BlockPos getOnPos(float offset) {
- if (this.mainSupportingBlockPos.isPresent()) {
+ if (this.mainSupportingBlockPos.isPresent() && this.level().getChunkIfLoadedImmediately(this.mainSupportingBlockPos.get()) != null) { // Paper - ensure no loads
BlockPos blockposition = (BlockPos) this.mainSupportingBlockPos.get();
if (offset <= 1.0E-5F) {

View file

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Thu, 6 Jul 2023 20:17:37 -0700
Subject: [PATCH] Optimize player lookups for beacons
For larger ranges, it's better to iterate over the player list
than the entity slices.
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
index c343ae1999672be8be0c982df2fadca8d05ebfa4..5c951ef93fe4cf4f085df86b0cefc02bc2610ab9 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
@@ -320,7 +320,16 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name
double d0 = blockEntity != null ? blockEntity.getEffectRange() : (i * 10 + 10);// Paper - custom beacon ranges
AABB axisalignedbb = (new AABB(blockposition)).inflate(d0).expandTowards(0.0D, (double) world.getHeight(), 0.0D);
- List<Player> list = world.getEntitiesOfClass(Player.class, axisalignedbb);
+ // Paper start - optimize player lookup for beacons
+ List<Player> list;
+ if (d0 <= 128.0) {
+ list = world.getEntitiesOfClass(Player.class, axisalignedbb);
+ } else {
+ list = (List)world.getNearbyPlayers(null, (double)blockposition.getX() + 0.5, (double)blockposition.getY() + 0.5, (double)blockposition.getZ() + 0.5, -1.0, (net.minecraft.world.entity.Entity entity) -> {
+ return !entity.isSpectator() && entity.getBoundingBox().intersects(axisalignedbb);
+ });
+ }
+ // Paper end - optimize player lookup for beacons
return list;
}

View file

@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Fri, 23 Jun 2023 12:16:28 -0700
Subject: [PATCH] Add Sign#getInteractableSideFor
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
index e34f7426df5d6c94fcc4101b28702e6c1d9fccff..9eea2982e92e9bc7a53962dc6b21de60f9e5a4c7 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/SignBlockEntity.java
@@ -64,13 +64,18 @@ public class SignBlockEntity extends BlockEntity implements CommandSource { // C
}
public boolean isFacingFrontText(net.minecraft.world.entity.player.Player player) {
+ // Paper start
+ return this.isFacingFrontText(player.getX(), player.getZ());
+ }
+ public boolean isFacingFrontText(double x, double z) {
+ // Paper end
Block block = this.getBlockState().getBlock();
if (block instanceof SignBlock) {
SignBlock blocksign = (SignBlock) block;
Vec3 vec3d = blocksign.getSignHitboxCenterPosition(this.getBlockState());
- double d0 = player.getX() - ((double) this.getBlockPos().getX() + vec3d.x);
- double d1 = player.getZ() - ((double) this.getBlockPos().getZ() + vec3d.z);
+ double d0 = x - ((double) this.getBlockPos().getX() + vec3d.x); // Paper
+ double d1 = z - ((double) this.getBlockPos().getZ() + vec3d.z); // Paper
float f = blocksign.getYRotationDegrees(this.getBlockState());
float f1 = (float) (Mth.atan2(d1, d0) * 57.2957763671875D) - 90.0F;
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
index 6d40e8a75126eff3f863ab6fbea8a85ab43ac9c9..c6c1ebe93a6977b4355db5551b0493b9ce53a61d 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSign.java
@@ -158,6 +158,14 @@ public class CraftSign<T extends SignBlockEntity> extends CraftBlockEntityState<
}
// Paper end
+ // Paper start - side facing API
+ @Override
+ public Side getInteractableSideFor(final double x, final double z) {
+ this.requirePlaced();
+ return this.getSnapshot().isFacingFrontText(x, z) ? Side.FRONT : Side.BACK;
+ }
+ // Paper end
+
public static Component[] sanitizeLines(String[] lines) {
Component[] components = new Component[4];

View file

@ -1,56 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: jellysquid3 <jellysquid3@users.noreply.github.com>
Date: Sat, 8 Jul 2023 21:38:05 +0200
Subject: [PATCH] Array backed synched entity data
Original code by jellysquid3 in Lithium, licensed under the GNU Lesser General Public License v3.0 (https://www.gnu.org/licenses/lgpl-3.0.html)
diff --git a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
index 15add3f4dfd718ec09bb1db4f22223466936879c..5dfb35117c285e0b202dc9c088ad5848beb8d054 100644
--- a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
+++ b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
@@ -34,6 +34,11 @@ public class SynchedEntityData {
private final Int2ObjectMap<SynchedEntityData.DataItem<?>> itemsById = new Int2ObjectOpenHashMap();
// private final ReadWriteLock lock = new ReentrantReadWriteLock(); // Spigot - not required
private boolean isDirty;
+ // Paper start - array backed synched entity data
+ private static final int DEFAULT_ENTRY_COUNT = 10;
+ private static final int GROW_FACTOR = 8;
+ private SynchedEntityData.DataItem<?>[] itemsArray = new SynchedEntityData.DataItem<?>[DEFAULT_ENTRY_COUNT];
+ // Paper end
public SynchedEntityData(Entity trackedEntity) {
this.entity = trackedEntity;
@@ -103,6 +108,15 @@ public class SynchedEntityData {
// this.lock.writeLock().lock(); // Spigot - not required
this.itemsById.put(key.getId(), datawatcher_item);
// this.lock.writeLock().unlock(); // Spigot - not required
+ // Paper start - array backed synched entity data
+ if (this.itemsArray.length <= key.getId()) {
+ final int newSize = Math.min(key.getId() + GROW_FACTOR, MAX_ID_VALUE);
+
+ this.itemsArray = java.util.Arrays.copyOf(this.itemsArray, newSize);
+ }
+
+ this.itemsArray[key.getId()] = datawatcher_item;
+ // Paper end
}
public <T> boolean hasItem(EntityDataAccessor<T> key) {
@@ -130,7 +144,15 @@ public class SynchedEntityData {
return datawatcher_item;
*/
- return (SynchedEntityData.DataItem) this.itemsById.get(key.getId());
+ // Paper start - array backed synched entity data
+ final int id = key.getId();
+
+ if (id < 0 || id >= this.itemsArray.length) {
+ return null;
+ }
+
+ return (DataItem<T>) this.itemsArray[id];
+ // Paper end
// Spigot end
}

View file

@ -1,74 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Tue, 11 Jul 2023 11:22:30 -0700
Subject: [PATCH] fix item meta for tadpole buckets
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
index 4c0b250bb9e3cf52173b563b36fd27d9e893e154..3f4e55bb9a4134e54adddca3c662285164068d95 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
@@ -348,6 +348,7 @@ public final class CraftItemFactory implements ItemFactory {
case COD_BUCKET:
case PUFFERFISH_BUCKET:
case SALMON_BUCKET:
+ case TADPOLE_BUCKET: // Paper
case ITEM_FRAME:
case GLOW_ITEM_FRAME:
case PAINTING:
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index ce82f313007762b6d1d9f006f21a8858e2976efb..0e5abd2a8694b24d4077a602a544e9c2b4c31822 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -600,6 +600,7 @@ public final class CraftItemStack extends ItemStack {
case COD_BUCKET:
case PUFFERFISH_BUCKET:
case SALMON_BUCKET:
+ case TADPOLE_BUCKET: // Paper
case ITEM_FRAME:
case GLOW_ITEM_FRAME:
case PAINTING:
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java
index e65bdbbbedb91eca016d46de5cc7cbb70dd9f659..9024467a627a40a145a951510f2207e2a175a4ab 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaEntityTag.java
@@ -16,6 +16,7 @@ public class CraftMetaEntityTag extends CraftMetaItem {
Material.COD_BUCKET,
Material.PUFFERFISH_BUCKET,
Material.SALMON_BUCKET,
+ Material.TADPOLE_BUCKET, // Paper
Material.ITEM_FRAME,
Material.GLOW_ITEM_FRAME,
Material.PAINTING
diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java
index 7cc7f485325a4277bac7a6eade749dbb3b0b104f..6930e7fdbe1f42020afb9c089c77da60408dacd7 100644
--- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java
+++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java
@@ -235,6 +235,27 @@ public class ItemMetaTest extends AbstractTestingBase {
}
}
+ // Paper start - check entity tag metas
+ private static final java.util.Set<Class<?>> ENTITY_TAG_METAS = java.util.Set.of(
+ CraftMetaEntityTag.class,
+ CraftMetaTropicalFishBucket.class,
+ CraftMetaAxolotlBucket.class
+ );
+ @Test
+ public void testEntityTagMeta() {
+ for (final Item item : BuiltInRegistries.ITEM) {
+ if (item instanceof net.minecraft.world.item.HangingEntityItem || item instanceof net.minecraft.world.item.MobBucketItem) {
+ ItemStack stack = new ItemStack(CraftMagicNumbers.getMaterial(item));
+ assertTrue("missing entity tag meta handling for " + item, ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()));
+ stack = CraftItemStack.asNewCraftStack(net.minecraft.world.item.Items.STONE);
+ stack.editMeta(meta -> meta.displayName(net.kyori.adventure.text.Component.text("hello")));
+ stack.setType(CraftMagicNumbers.getMaterial(item));
+ assertTrue("missing entity tag meta handling for " + item, ENTITY_TAG_METAS.contains(stack.getItemMeta().getClass()));
+ }
+ }
+ }
+ // Paper end
+
@Test
public void testEachExtraData() {
final List<StackProvider> providers = Arrays.asList(