1037
This commit is contained in:
parent
227caac7f0
commit
afbb0d88dd
15 changed files with 156 additions and 145 deletions
|
@ -1,73 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: masmc05 <masmc05@gmail.com>
|
||||
Date: Sun, 11 Aug 2024 03:01:52 +0300
|
||||
Subject: [PATCH] Item serialization as json
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/item/component/CustomData.java b/src/main/java/net/minecraft/world/item/component/CustomData.java
|
||||
index 6b7245cf05ea4b6ce05462eb3164bce7f5d76a03..ac1914438307e8a7cc3a3b6352e88a0638f8a33b 100644
|
||||
--- a/src/main/java/net/minecraft/world/item/component/CustomData.java
|
||||
+++ b/src/main/java/net/minecraft/world/item/component/CustomData.java
|
||||
@@ -28,7 +28,17 @@ import org.slf4j.Logger;
|
||||
public final class CustomData {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final CustomData EMPTY = new CustomData(new CompoundTag());
|
||||
- public static final Codec<CustomData> CODEC = Codec.withAlternative(CompoundTag.CODEC, TagParser.AS_CODEC)
|
||||
+ // Paper start - Item serialization as json
|
||||
+ public static ThreadLocal<Boolean> SERIALIZE_CUSTOM_AS_SNBT = ThreadLocal.withInitial(() -> false);
|
||||
+ public static final Codec<CustomData> CODEC = Codec.either(CompoundTag.CODEC, TagParser.AS_CODEC)
|
||||
+ .xmap(com.mojang.datafixers.util.Either::unwrap, data -> { // Both will be used for deserialization, but we decide which one to use for serialization
|
||||
+ if (!SERIALIZE_CUSTOM_AS_SNBT.get()) {
|
||||
+ return com.mojang.datafixers.util.Either.left(data); // First codec
|
||||
+ } else {
|
||||
+ return com.mojang.datafixers.util.Either.right(data); // Second codec
|
||||
+ }
|
||||
+ })
|
||||
+ // Paper end - Item serialization as json
|
||||
.xmap(CustomData::new, component -> component.tag);
|
||||
public static final Codec<CustomData> CODEC_WITH_ID = CODEC.validate(
|
||||
component -> component.getUnsafe().contains("id", 8) ? DataResult.success(component) : DataResult.error(() -> "Missing id for entity in: " + component)
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
index 8b2dbdfcdc4e98602f6bfd48d2c53840730f4691..d06aab9bd5cd901c8367f9680f5d27ddb17b3dc4 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||
@@ -511,6 +511,39 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||
return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.parse(MinecraftServer.getServer().registryAccess(), compound).orElseThrow());
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public com.google.gson.JsonObject serializeItemAsJson(ItemStack itemStack) {
|
||||
+ Preconditions.checkNotNull(itemStack, "Cannot serialize empty ItemStack");
|
||||
+ Preconditions.checkArgument(!itemStack.isEmpty(), "Cannot serialize empty ItemStack");
|
||||
+
|
||||
+ net.minecraft.core.RegistryAccess.Frozen reg = net.minecraft.server.MinecraftServer.getServer().registryAccess();
|
||||
+ com.mojang.serialization.DynamicOps<com.google.gson.JsonElement> ops = reg.createSerializationContext(com.mojang.serialization.JsonOps.INSTANCE);
|
||||
+ com.google.gson.JsonObject item;
|
||||
+ // Serialize as SNBT to preserve exact NBT types; vanilla codecs already can handle such deserialization.
|
||||
+ net.minecraft.world.item.component.CustomData.SERIALIZE_CUSTOM_AS_SNBT.set(true);
|
||||
+ try {
|
||||
+ item = net.minecraft.world.item.ItemStack.CODEC.encodeStart(ops, CraftItemStack.unwrap(itemStack)).getOrThrow().getAsJsonObject();
|
||||
+ } finally {
|
||||
+ net.minecraft.world.item.component.CustomData.SERIALIZE_CUSTOM_AS_SNBT.set(false);
|
||||
+ }
|
||||
+ item.addProperty("DataVersion", this.getDataVersion());
|
||||
+ return item;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ItemStack deserializeItemFromJson(com.google.gson.JsonObject data) throws IllegalArgumentException {
|
||||
+ Preconditions.checkNotNull(data, "null cannot be deserialized");
|
||||
+
|
||||
+ final int dataVersion = data.get("DataVersion").getAsInt();
|
||||
+ final int currentVersion = org.bukkit.craftbukkit.util.CraftMagicNumbers.INSTANCE.getDataVersion();
|
||||
+ data = ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertJson(
|
||||
+ ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ITEM_STACK,
|
||||
+ data, false, dataVersion, currentVersion
|
||||
+ );
|
||||
+ com.mojang.serialization.DynamicOps<com.google.gson.JsonElement> ops = MinecraftServer.getServer().registryAccess().createSerializationContext(com.mojang.serialization.JsonOps.INSTANCE);
|
||||
+ return CraftItemStack.asCraftMirror(net.minecraft.world.item.ItemStack.CODEC.parse(ops, data).getOrThrow(IllegalArgumentException::new));
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public byte[] serializeEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity, "null cannot be serialized");
|
|
@ -1,26 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: strnq <dev@aruus.uk>
|
||||
Date: Sat, 14 Sep 2024 12:53:13 +0300
|
||||
Subject: [PATCH] Validate slot in PlayerInventory#setSlot
|
||||
|
||||
The CraftPlayerInventory implementation sends a container_set_slot
|
||||
packet to the client which will error if an invalid slot is passed to
|
||||
the setSlot method, making a validation necessary over simply silently
|
||||
ignoring invalid slot values.
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java
|
||||
index eafa54c870c3e2aef30c3f9f96f516607a7cae24..8dea4321e41080829b474ad7b5a12c6a622181fd 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryPlayer.java
|
||||
@@ -70,6 +70,11 @@ public class CraftInventoryPlayer extends CraftInventory implements org.bukkit.i
|
||||
|
||||
@Override
|
||||
public void setItem(int index, ItemStack item) {
|
||||
+ // Paper start - Validate setItem index
|
||||
+ if (index < 0 || index > 40) {
|
||||
+ throw new ArrayIndexOutOfBoundsException("Index must be between 0 and 40");
|
||||
+ }
|
||||
+ // Paper end - Validate setItem index
|
||||
super.setItem(index, item);
|
||||
if (this.getHolder() == null) return;
|
||||
ServerPlayer player = ((CraftPlayer) this.getHolder()).getHandle();
|
|
@ -1,163 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bjarne Koll <lynxplay101@gmail.com>
|
||||
Date: Mon, 16 Sep 2024 23:07:29 +0200
|
||||
Subject: [PATCH] Remove wall-time / unused skip tick protection
|
||||
|
||||
Spigot still maintains some partial implementation of "tick skipping", a
|
||||
practice in which the MinecraftServer.currentTick field is updated not
|
||||
by an increment of one per actual tick, but instead set to
|
||||
System.currentTimeMillis() / 50. This behaviour means that the tracked
|
||||
tick may "skip" a tick value in case a previous tick took more than the
|
||||
expected 50ms.
|
||||
|
||||
To compensate for this in important paths, spigot/craftbukkit
|
||||
implements "wall-time". Instead of incrementing/decrementing ticks on
|
||||
block entities/entities by one for each call to their tick() method,
|
||||
they instead increment/decrement important values, like
|
||||
an ItemEntity's age or pickupDelay, by the difference of
|
||||
`currentTick - lastTick`, where `lastTick` is the value of
|
||||
`currentTick` during the last tick() call.
|
||||
|
||||
These "fixes" however do not play nicely with minecraft's simulation
|
||||
distance as entities/block entities implementing the above behaviour
|
||||
would "catch up" their values when moving from a non-ticking chunk to a
|
||||
ticking one as their `lastTick` value remains stuck on the last tick in
|
||||
a ticking chunk and hence lead to a large "catch up" once ticked again.
|
||||
|
||||
Paper completely removes the "tick skipping" behaviour (See patch
|
||||
"Further-improve-server-tick-loop"), making the above precautions
|
||||
completely unnecessary, which also rids paper of the previous described
|
||||
incompatibility with non-ticking chunks.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index 03cfa29bdb426a9fb6b1b6be6e897da48d4f2f3e..4423973d4d9a2c3879d98d1d4c8b8c117c677ac5 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -60,7 +60,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
@Nullable
|
||||
public UUID target;
|
||||
public final float bobOffs;
|
||||
- private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit
|
||||
+ // private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit // Paper - remove anti tick skipping measures / wall time
|
||||
public boolean canMobPickup = true; // Paper - Item#canEntityPickup
|
||||
private int despawnRate = -1; // Paper - Alternative item-despawn-rate
|
||||
public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API
|
||||
@@ -153,12 +153,11 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
} else {
|
||||
super.tick();
|
||||
- // CraftBukkit start - Use wall time for pickup and despawn timers
|
||||
- int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
- if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
||||
- if (this.age != -32768) this.age += elapsedTicks;
|
||||
- this.lastTick = MinecraftServer.currentTick;
|
||||
- // CraftBukkit end
|
||||
+ // Paper start - remove anti tick skipping measures / wall time - revert to vanilla
|
||||
+ if (this.pickupDelay > 0 && this.pickupDelay != 32767) {
|
||||
+ --this.pickupDelay;
|
||||
+ }
|
||||
+ // Paper end - remove anti tick skipping measures / wall time - revert to vanilla
|
||||
|
||||
this.xo = this.getX();
|
||||
this.yo = this.getY();
|
||||
@@ -211,7 +210,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
this.mergeWithNeighbours();
|
||||
}
|
||||
|
||||
- /* CraftBukkit start - moved up
|
||||
+ // Paper - remove anti tick skipping measures / wall time - revert to vanilla /* CraftBukkit start - moved up
|
||||
if (this.age != -32768) {
|
||||
++this.age;
|
||||
}
|
||||
@@ -242,12 +241,14 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
// Spigot start - copied from above
|
||||
@Override
|
||||
public void inactiveTick() {
|
||||
- // CraftBukkit start - Use wall time for pickup and despawn timers
|
||||
- int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
- if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
||||
- if (this.age != -32768) this.age += elapsedTicks;
|
||||
- this.lastTick = MinecraftServer.currentTick;
|
||||
- // CraftBukkit end
|
||||
+ // Paper start - remove anti tick skipping measures / wall time - copied from above
|
||||
+ if (this.pickupDelay > 0 && this.pickupDelay != 32767) {
|
||||
+ --this.pickupDelay;
|
||||
+ }
|
||||
+ if (this.age != -32768) {
|
||||
+ ++this.age;
|
||||
+ }
|
||||
+ // Paper end - remove anti tick skipping measures / wall time - copied from above
|
||||
|
||||
if (!this.level().isClientSide && this.age >= this.despawnRate) { // Spigot // Paper - Alternative item-despawn-rate
|
||||
// CraftBukkit start - fire ItemDespawnEvent
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
index 2280004638fd19ed018cb3e77d53a018b34ec516..2b43337ac63d051718a2074fcc46e128a1d65129 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -96,7 +96,7 @@ public class Zombie extends Monster {
|
||||
private boolean canBreakDoors;
|
||||
private int inWaterTime;
|
||||
public int conversionTime;
|
||||
- private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field
|
||||
+ // private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field // Paper - remove anti tick skipping measures / wall time
|
||||
private boolean shouldBurnInDay = true; // Paper - Add more Zombie API
|
||||
|
||||
public Zombie(EntityType<? extends Zombie> type, Level world) {
|
||||
@@ -219,10 +219,7 @@ public class Zombie extends Monster {
|
||||
public void tick() {
|
||||
if (!this.level().isClientSide && this.isAlive() && !this.isNoAi()) {
|
||||
if (this.isUnderWaterConverting()) {
|
||||
- // CraftBukkit start - Use wall time instead of ticks for conversion
|
||||
- int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
||||
- this.conversionTime -= elapsedTicks;
|
||||
- // CraftBukkit end
|
||||
+ --this.conversionTime; // Paper - remove anti tick skipping measures / wall time
|
||||
if (this.conversionTime < 0) {
|
||||
this.doUnderWaterConversion();
|
||||
}
|
||||
@@ -239,7 +236,7 @@ public class Zombie extends Monster {
|
||||
}
|
||||
|
||||
super.tick();
|
||||
- this.lastTick = MinecraftServer.currentTick; // CraftBukkit
|
||||
+ // this.lastTick = MinecraftServer.currentTick; // CraftBukkit // Paper - remove anti tick skipping measures / wall time
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -280,7 +277,7 @@ public class Zombie extends Monster {
|
||||
}
|
||||
// Paper end - Add more Zombie API
|
||||
public void startUnderWaterConversion(int ticksUntilWaterConversion) {
|
||||
- this.lastTick = MinecraftServer.currentTick; // CraftBukkit
|
||||
+ // this.lastTick = MinecraftServer.currentTick; // CraftBukkit // Paper - remove anti tick skipping measures / wall time
|
||||
this.conversionTime = ticksUntilWaterConversion;
|
||||
this.getEntityData().set(Zombie.DATA_DROWNED_CONVERSION_ID, true);
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
|
||||
index a2fafef89d5354e2cb02f5672810909950a57777..bf2c303a314205590a2839e0f729af3a9ff40a86 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
|
||||
@@ -54,7 +54,7 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
|
||||
public int fuel;
|
||||
protected final ContainerData dataAccess;
|
||||
// CraftBukkit start - add fields and methods
|
||||
- private int lastTick = MinecraftServer.currentTick;
|
||||
+ // private int lastTick = MinecraftServer.currentTick; // Paper - remove anti tick skipping measures / wall time
|
||||
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
||||
private int maxStack = MAX_STACK;
|
||||
|
||||
@@ -169,12 +169,10 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
|
||||
boolean flag1 = blockEntity.brewTime > 0;
|
||||
ItemStack itemstack1 = (ItemStack) blockEntity.items.get(3);
|
||||
|
||||
- // CraftBukkit start - Use wall time instead of ticks for brewing
|
||||
- int elapsedTicks = MinecraftServer.currentTick - blockEntity.lastTick;
|
||||
- blockEntity.lastTick = MinecraftServer.currentTick;
|
||||
+ // Paper - remove anti tick skipping measures / wall time
|
||||
|
||||
if (flag1) {
|
||||
- blockEntity.brewTime -= elapsedTicks;
|
||||
+ --blockEntity.brewTime; // Paper - remove anti tick skipping measures / wall time - revert to vanilla
|
||||
boolean flag2 = blockEntity.brewTime <= 0; // == -> <=
|
||||
// CraftBukkit end
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Newwind <support@newwindserver.com>
|
||||
Date: Fri, 20 Sep 2024 14:17:37 +0200
|
||||
Subject: [PATCH] Disable pretty printing for advancement saving
|
||||
|
||||
Reduces json size by about 25%
|
||||
Not sure why advancements even had pretty printing enabled.
|
||||
My best guess was by accident on mojang's part, especially since stats json files don't have pretty printing.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
index 9fabf9322acd663c4452b562494e74aa42eb19da..862a4bf003b7f810fb57dbcd150a1417c902b633 100644
|
||||
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
|
||||
@@ -50,7 +50,7 @@ import org.slf4j.Logger;
|
||||
public class PlayerAdvancements {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
- private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().create();
|
||||
+ private static final Gson GSON = (new GsonBuilder()).create(); // Paper - Remove pretty printing from advancements
|
||||
private final PlayerList playerList;
|
||||
private final Path playerSavePath;
|
||||
private AdvancementTree tree;
|
|
@ -1,52 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Nassim Jahnke <nassim@njahnke.dev>
|
||||
Date: Sat, 21 Sep 2024 22:01:52 +0200
|
||||
Subject: [PATCH] Fix PlayerCommandPreprocessEvent on signed commands
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index fcccf989c25f0a259b160c4ff7873f7009e64d14..befeaac4786760f6847a5945da2296a3e68dbb17 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2245,24 +2245,32 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), command, new LazyPlayerSet(this.server));
|
||||
this.cserver.getPluginManager().callEvent(event);
|
||||
-
|
||||
- if (event.isCancelled()) {
|
||||
- return;
|
||||
- }
|
||||
command = event.getMessage().substring(1);
|
||||
|
||||
- ParseResults<CommandSourceStack> parseresults = this.parseCommand(command);
|
||||
- // CraftBukkit end
|
||||
-
|
||||
- Map map;
|
||||
+ // Paper start - Fix cancellation and message changing
|
||||
+ ParseResults<CommandSourceStack> parseresults = this.parseCommand(packet.command());
|
||||
|
||||
+ Map<String, PlayerChatMessage> map;
|
||||
try {
|
||||
- map = (packet.command().equals(command)) ? this.collectSignedArguments(packet, SignableCommand.of(parseresults), lastSeenMessages) : Collections.emptyMap(); // CraftBukkit
|
||||
+ // Always parse the original command to add to the chat chain
|
||||
+ map = this.collectSignedArguments(packet, SignableCommand.of(parseresults), lastSeenMessages);
|
||||
} catch (SignedMessageChain.DecodeException signedmessagechain_a) {
|
||||
this.handleMessageDecodeFailure(signedmessagechain_a);
|
||||
return;
|
||||
}
|
||||
|
||||
+ if (event.isCancelled()) {
|
||||
+ // Only now are we actually good to return
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ // Remove signed parts if the command was changed
|
||||
+ if (!command.equals(packet.command())) {
|
||||
+ parseresults = this.parseCommand(command);
|
||||
+ map = Collections.emptyMap();
|
||||
+ }
|
||||
+ // Paper end - Fix cancellation and message changing
|
||||
+
|
||||
CommandSigningContext.SignedArguments commandsigningcontext_a = new CommandSigningContext.SignedArguments(map);
|
||||
|
||||
parseresults = Commands.<CommandSourceStack>mapSource(parseresults, (commandlistenerwrapper) -> { // CraftBukkit - decompile error
|
|
@ -1,33 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: masmc05 <masmc05@gmail.com>
|
||||
Date: Wed, 25 Sep 2024 16:26:04 +0300
|
||||
Subject: [PATCH] Add enchantWithLevels with enchantment registry set
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
|
||||
index fef91dbede067f1ab99a9c7d463a2c55cc6cae3a..4abd939223a9d5a0c52a64e22c29fe1de85500e9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
|
||||
@@ -319,6 +319,22 @@ public final class CraftItemFactory implements ItemFactory {
|
||||
);
|
||||
}
|
||||
|
||||
+ @Override
|
||||
+ public ItemStack enchantWithLevels(ItemStack itemStack, int levels, io.papermc.paper.registry.set.RegistryKeySet<org.bukkit.enchantments.Enchantment> keySet, java.util.Random random) {
|
||||
+ return enchantWithLevels(
|
||||
+ itemStack,
|
||||
+ levels,
|
||||
+ Optional.of(
|
||||
+ io.papermc.paper.registry.set.PaperRegistrySets.convertToNms(
|
||||
+ Registries.ENCHANTMENT,
|
||||
+ net.minecraft.server.MinecraftServer.getServer().registryAccess().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE).lookupProvider,
|
||||
+ keySet
|
||||
+ )
|
||||
+ ),
|
||||
+ random
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
|
||||
private ItemStack enchantWithLevels(
|
||||
ItemStack itemStack,
|
|
@ -1,154 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Fri, 27 Sep 2024 17:13:16 -0700
|
||||
Subject: [PATCH] Improve entity effect API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index cd789c235acf740ec29c30b180e7fbe1a140caa9..89c8713d2c2206d1b0d8c0a392c9d13b3e736f0c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -1299,4 +1299,15 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
return this.getHandle().getScoreboardName();
|
||||
}
|
||||
// Paper end - entity scoreboard name
|
||||
+
|
||||
+ // Paper start - broadcast hurt animation
|
||||
+ @Override
|
||||
+ public void broadcastHurtAnimation(java.util.Collection<Player> players) {
|
||||
+ //noinspection SuspiciousMethodCalls
|
||||
+ Preconditions.checkArgument(!players.contains(this), "Cannot broadcast hurt animation to self without a yaw");
|
||||
+ for (final org.bukkit.entity.Player player : players) {
|
||||
+ ((CraftPlayer) player).sendHurtAnimation(0, this);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - broadcast hurt animation
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index ad740739437be632fc7fedec488a7d0c49534688..42d7660efe5baa6f796f2a7606686c765b6f2478 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -1277,6 +1277,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public void sendHurtAnimation(float yaw) {
|
||||
+ // Paper start - Add target entity to sendHurtAnimation
|
||||
+ this.sendHurtAnimation(yaw, this);
|
||||
+ }
|
||||
+ public void sendHurtAnimation(float yaw, org.bukkit.entity.Entity target) {
|
||||
+ // Paper end - Add target entity to sendHurtAnimation
|
||||
if (this.getHandle().connection == null) {
|
||||
return;
|
||||
}
|
||||
@@ -1286,7 +1291,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
* This makes no sense. We'll add 90 to it so that 0 = front, clockwise from there.
|
||||
*/
|
||||
float actualYaw = yaw + 90;
|
||||
- this.getHandle().connection.send(new ClientboundHurtAnimationPacket(this.getEntityId(), actualYaw));
|
||||
+ this.getHandle().connection.send(new ClientboundHurtAnimationPacket(target.getEntityId(), actualYaw)); // Paper - Add target entity to sendHurtAnimation
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3553,4 +3558,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer)this.getHandle())
|
||||
.moonrise$getViewDistanceHolder().setSendViewDistance(viewDistance);
|
||||
}
|
||||
+
|
||||
+ // Paper start - entity effect API
|
||||
+ @Override
|
||||
+ public void sendEntityEffect(final org.bukkit.EntityEffect effect, final org.bukkit.entity.Entity target) {
|
||||
+ if (this.getHandle().connection == null || !effect.isApplicableTo(target)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundEntityEventPacket(((CraftEntity) target).getHandle(), effect.getData()));
|
||||
+ }
|
||||
+ // Paper end - entity effect API
|
||||
}
|
||||
diff --git a/src/test/java/org/bukkit/EntityEffectTest.java b/src/test/java/org/bukkit/EntityEffectTest.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..5e64dfaeba167374dc45c5becfb2e7114657dff6
|
||||
--- /dev/null
|
||||
+++ b/src/test/java/org/bukkit/EntityEffectTest.java
|
||||
@@ -0,0 +1,82 @@
|
||||
+package org.bukkit;
|
||||
+
|
||||
+import com.google.common.base.Joiner;
|
||||
+import java.lang.reflect.Field;
|
||||
+import java.lang.reflect.Modifier;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.HashSet;
|
||||
+import java.util.List;
|
||||
+import java.util.Map;
|
||||
+import java.util.Set;
|
||||
+import net.minecraft.world.entity.EntityEvent;
|
||||
+import org.bukkit.support.environment.Normal;
|
||||
+import org.junit.jupiter.api.Test;
|
||||
+
|
||||
+import static org.junit.jupiter.api.Assertions.fail;
|
||||
+
|
||||
+@Normal
|
||||
+public class EntityEffectTest {
|
||||
+
|
||||
+ private static List<Byte> collectNmsLevelEvents() throws ReflectiveOperationException {
|
||||
+ final List<Byte> events = new ArrayList<>();
|
||||
+ for (final Field field : EntityEvent.class.getFields()) {
|
||||
+ if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && field.getType() == byte.class) {
|
||||
+ events.add((byte) field.get(null));
|
||||
+ }
|
||||
+ }
|
||||
+ for (int i = 22; i <= 28; i++) {
|
||||
+ events.remove(Byte.valueOf((byte) i)); // all have existing API (debug info and op level)
|
||||
+ }
|
||||
+ events.remove(Byte.valueOf(EntityEvent.STOP_ATTACKING)); // not used on client anywhere
|
||||
+ events.remove(Byte.valueOf(EntityEvent.USE_ITEM_COMPLETE)); // not suitable for API (complete using item on Player)
|
||||
+ events.remove(Byte.valueOf(EntityEvent.FISHING_ROD_REEL_IN)); // not suitable for API (fishing rod reel in on FishingHook)
|
||||
+ events.add((byte) 0); // handled on Arrow (for some reason it's not in the EntityEvent nms file as a constant)
|
||||
+ return events;
|
||||
+ }
|
||||
+
|
||||
+ private static boolean isNotDeprecated(EntityEffect effect) throws ReflectiveOperationException {
|
||||
+ return !EntityEffect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class);
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void checkAllApiExists() throws ReflectiveOperationException {
|
||||
+ Map<Byte, EntityEffect> toId = new HashMap<>();
|
||||
+ for (final EntityEffect effect : EntityEffect.values()) {
|
||||
+ if (isNotDeprecated(effect)) {
|
||||
+ toId.put(effect.getData(), effect);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final Set<Byte> missingEvents = new HashSet<>();
|
||||
+ for (final Byte event : collectNmsLevelEvents()) {
|
||||
+ if (toId.get(event) == null) {
|
||||
+ missingEvents.add(event);
|
||||
+ }
|
||||
+ }
|
||||
+ if (!missingEvents.isEmpty()) {
|
||||
+ fail("Missing API EntityEffects:\n" + Joiner.on("\n").join(missingEvents));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Test
|
||||
+ public void checkNoExtraApi() throws ReflectiveOperationException {
|
||||
+ Map<Byte, EntityEffect> toId = new HashMap<>();
|
||||
+ for (final EntityEffect effect : EntityEffect.values()) {
|
||||
+ if (isNotDeprecated(effect)) {
|
||||
+ toId.put(effect.getData(), effect);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final List<Byte> nmsEvents = collectNmsLevelEvents();
|
||||
+ final Set<EntityEffect> extraApiEffects = new HashSet<>();
|
||||
+ for (final Map.Entry<Byte, EntityEffect> entry : toId.entrySet()) {
|
||||
+ if (!nmsEvents.contains(entry.getKey())) {
|
||||
+ extraApiEffects.add(entry.getValue());
|
||||
+ }
|
||||
+ }
|
||||
+ if (!extraApiEffects.isEmpty()) {
|
||||
+ fail("Extra API EntityEffects:\n" + Joiner.on("\n").join(extraApiEffects));
|
||||
+ }
|
||||
+ }
|
||||
+}
|
|
@ -1,181 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tamion <70228790+notTamion@users.noreply.github.com>
|
||||
Date: Sun, 15 Sep 2024 19:17:12 +0200
|
||||
Subject: [PATCH] Add recipeBrewTime
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.inventory.BrewingStandMenu brewingStandData
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/inventory/BrewingSimpleContainerData.java b/src/main/java/io/papermc/paper/inventory/BrewingSimpleContainerData.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..84dead75191634c3aa6031781a2ff3087171793b
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/inventory/BrewingSimpleContainerData.java
|
||||
@@ -0,0 +1,11 @@
|
||||
+package io.papermc.paper.inventory;
|
||||
+
|
||||
+import net.minecraft.world.inventory.SimpleContainerData;
|
||||
+
|
||||
+public class BrewingSimpleContainerData extends SimpleContainerData {
|
||||
+
|
||||
+ public BrewingSimpleContainerData() {
|
||||
+ super(3);
|
||||
+ this.set(2, 400);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java b/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java
|
||||
index 68c529cb38d61cd3a0f39bef0f666057fc219c9b..6ec207e91f93b3ab625515dc75367ba399818876 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/BrewingStandMenu.java
|
||||
@@ -41,14 +41,14 @@ public class BrewingStandMenu extends AbstractContainerMenu {
|
||||
// CraftBukkit end
|
||||
|
||||
public BrewingStandMenu(int syncId, Inventory playerInventory) {
|
||||
- this(syncId, playerInventory, new SimpleContainer(5), new SimpleContainerData(2));
|
||||
+ this(syncId, playerInventory, new SimpleContainer(5), new io.papermc.paper.inventory.BrewingSimpleContainerData()); // Paper - Add totalBrewTime
|
||||
}
|
||||
|
||||
public BrewingStandMenu(int syncId, Inventory playerInventory, Container inventory, ContainerData propertyDelegate) {
|
||||
super(MenuType.BREWING_STAND, syncId);
|
||||
this.player = playerInventory; // CraftBukkit
|
||||
checkContainerSize(inventory, 5);
|
||||
- checkContainerDataCount(propertyDelegate, 2);
|
||||
+ checkContainerDataCount(propertyDelegate, 3); // Paper - Add recipeBrewTime
|
||||
this.brewingStand = inventory;
|
||||
this.brewingStandData = propertyDelegate;
|
||||
PotionBrewing potionbrewer = playerInventory.player.level().potionBrewing();
|
||||
@@ -60,7 +60,20 @@ public class BrewingStandMenu extends AbstractContainerMenu {
|
||||
// Paper end - custom potion mixes
|
||||
this.ingredientSlot = this.addSlot(new BrewingStandMenu.IngredientsSlot(potionbrewer, inventory, 3, 79, 17));
|
||||
this.addSlot(new BrewingStandMenu.FuelSlot(inventory, 4, 17, 17));
|
||||
- this.addDataSlots(propertyDelegate);
|
||||
+ // Paper start - Add recipeBrewTime
|
||||
+ this.addDataSlots(new SimpleContainerData(2) {
|
||||
+ @Override
|
||||
+ public int get(final int index) {
|
||||
+ if (index == 0) return 400 * propertyDelegate.get(index) / propertyDelegate.get(2);
|
||||
+ return propertyDelegate.get(index);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void set(final int index, final int value) {
|
||||
+ propertyDelegate.set(index, value);
|
||||
+ }
|
||||
+ });
|
||||
+ // Paper end - Add recipeBrewTime
|
||||
|
||||
int j;
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
|
||||
index bf2c303a314205590a2839e0f729af3a9ff40a86..0a93bacd62249bae1800ff306b8a7c765b0e5a8b 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java
|
||||
@@ -49,6 +49,7 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
|
||||
public static final int NUM_DATA_VALUES = 2;
|
||||
private NonNullList<ItemStack> items;
|
||||
public int brewTime;
|
||||
+ public int recipeBrewTime = 400; // Paper - Add recipeBrewTime
|
||||
private boolean[] lastPotionCount;
|
||||
private Item ingredient;
|
||||
public int fuel;
|
||||
@@ -99,6 +100,11 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
|
||||
case 1:
|
||||
j = BrewingStandBlockEntity.this.fuel;
|
||||
break;
|
||||
+ // Paper start - Add recipeBrewTime
|
||||
+ case 2:
|
||||
+ j = BrewingStandBlockEntity.this.recipeBrewTime;
|
||||
+ break;
|
||||
+ // Paper end - Add recipeBrewTime
|
||||
default:
|
||||
j = 0;
|
||||
}
|
||||
@@ -114,13 +120,18 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
|
||||
break;
|
||||
case 1:
|
||||
BrewingStandBlockEntity.this.fuel = value;
|
||||
+ // Paper start - Add recipeBrewTime
|
||||
+ case 2:
|
||||
+ BrewingStandBlockEntity.this.recipeBrewTime = value;
|
||||
+ break;
|
||||
+ // Paper end - Add recipeBrewTime
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
- return 2;
|
||||
+ return 3; // Paper - Add recipeBrewTime
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -188,7 +199,8 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements
|
||||
// CraftBukkit start
|
||||
BrewingStartEvent event = new BrewingStartEvent(CraftBlock.at(world, pos), CraftItemStack.asCraftMirror(itemstack1), 400);
|
||||
world.getCraftServer().getPluginManager().callEvent(event);
|
||||
- blockEntity.brewTime = event.getTotalBrewTime(); // 400 -> event.getTotalBrewTime()
|
||||
+ blockEntity.recipeBrewTime = event.getRecipeBrewTime(); // Paper - use recipe brew time from event
|
||||
+ blockEntity.brewTime = event.getBrewingTime(); // 400 -> event.getTotalBrewTime() // Paper - use brewing time from event
|
||||
// CraftBukkit end
|
||||
blockEntity.ingredient = itemstack1.getItem();
|
||||
setChanged(world, pos, state);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java
|
||||
index e9f55c898de827afe6c9f951cbe1b46eea5f4149..f330c17b11566102b4db430fef013101b3275bda 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBrewingStand.java
|
||||
@@ -41,6 +41,19 @@ public class CraftBrewingStand extends CraftContainer<BrewingStandBlockEntity> i
|
||||
this.getSnapshot().brewTime = brewTime;
|
||||
}
|
||||
|
||||
+ // Paper start - Add recipeBrewTime
|
||||
+ @Override
|
||||
+ public void setRecipeBrewTime(int recipeBrewTime) {
|
||||
+ com.google.common.base.Preconditions.checkArgument(recipeBrewTime > 0, "recipeBrewTime must be positive");
|
||||
+ this.getSnapshot().recipeBrewTime = recipeBrewTime;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getRecipeBrewTime() {
|
||||
+ return this.getSnapshot().recipeBrewTime;
|
||||
+ }
|
||||
+ // Paper end - Add recipeBrewTime
|
||||
+
|
||||
@Override
|
||||
public int getFuelLevel() {
|
||||
return this.getSnapshot().fuel;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
||||
index 674e3a827f8fb64e5c0beefb3c1874d6e8aee4e5..6d3f9d5dab6c9a2860ae31cae24310aa2d62da7c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java
|
||||
@@ -163,7 +163,7 @@ public class CraftContainer extends AbstractContainerMenu {
|
||||
this.delegate = new EnchantmentMenu(windowId, bottom);
|
||||
break;
|
||||
case BREWING:
|
||||
- this.delegate = new BrewingStandMenu(windowId, bottom, top, new SimpleContainerData(2));
|
||||
+ this.delegate = new BrewingStandMenu(windowId, bottom, top, new io.papermc.paper.inventory.BrewingSimpleContainerData()); // Paper - Add recipeBrewTime
|
||||
break;
|
||||
case HOPPER:
|
||||
this.delegate = new HopperMenu(windowId, bottom, top);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftBrewingStandView.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftBrewingStandView.java
|
||||
index aeb5a9c996ba6b6d812735bc78e3e5aec2c9d269..6e88347d74f6bd20d7808e0d556997ab73861e7c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftBrewingStandView.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftBrewingStandView.java
|
||||
@@ -35,4 +35,17 @@ public class CraftBrewingStandView extends CraftInventoryView<BrewingStandMenu,
|
||||
Preconditions.checkArgument(brewingTicks > 0, "The given brewing ticks must be greater than 0");
|
||||
this.container.setData(BrewingStandBlockEntity.DATA_BREW_TIME, brewingTicks);
|
||||
}
|
||||
+
|
||||
+ // Paper start - Add recipeBrewTime
|
||||
+ @Override
|
||||
+ public void setRecipeBrewTime(int recipeBrewTime) {
|
||||
+ com.google.common.base.Preconditions.checkArgument(recipeBrewTime > 0, "recipeBrewTime must be positive");
|
||||
+ this.container.brewingStandData.set(2, recipeBrewTime);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getRecipeBrewTime() {
|
||||
+ return this.container.brewingStandData.get(2);
|
||||
+ }
|
||||
+ // Paper end - Add recipeBrewTime
|
||||
}
|
|
@ -1,190 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sun, 16 Jan 2022 10:13:33 -0800
|
||||
Subject: [PATCH] Call bucket events for cauldrons
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java
|
||||
index f301c20e808b77cb3fcffd9a7c8102928306456e..b584cfe44fbb93d470ca56c091423833c4007d16 100644
|
||||
--- a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java
|
||||
+++ b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java
|
||||
@@ -60,7 +60,7 @@ public interface CauldronInteraction {
|
||||
static CauldronInteraction.InteractionMap newInteractionMap(String name) {
|
||||
Object2ObjectOpenHashMap<Item, CauldronInteraction> object2objectopenhashmap = new Object2ObjectOpenHashMap();
|
||||
|
||||
- object2objectopenhashmap.defaultReturnValue((iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
+ object2objectopenhashmap.defaultReturnValue((iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
|
||||
});
|
||||
CauldronInteraction.InteractionMap cauldroninteraction_a = new CauldronInteraction.InteractionMap(name, object2objectopenhashmap);
|
||||
@@ -69,13 +69,13 @@ public interface CauldronInteraction {
|
||||
return cauldroninteraction_a;
|
||||
}
|
||||
|
||||
- ItemInteractionResult interact(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack);
|
||||
+ ItemInteractionResult interact(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, final net.minecraft.core.Direction hitDirection); // Paper - add hitDirection
|
||||
|
||||
static void bootStrap() {
|
||||
Map<Item, CauldronInteraction> map = CauldronInteraction.EMPTY.map();
|
||||
|
||||
CauldronInteraction.addDefaultInteractions(map);
|
||||
- map.put(Items.POTION, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
+ map.put(Items.POTION, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
PotionContents potioncontents = (PotionContents) itemstack.get(DataComponents.POTION_CONTENTS);
|
||||
|
||||
if (potioncontents != null && potioncontents.is(Potions.WATER)) {
|
||||
@@ -103,12 +103,12 @@ public interface CauldronInteraction {
|
||||
Map<Item, CauldronInteraction> map1 = CauldronInteraction.WATER.map();
|
||||
|
||||
CauldronInteraction.addDefaultInteractions(map1);
|
||||
- map1.put(Items.BUCKET, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
+ map1.put(Items.BUCKET, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
return CauldronInteraction.fillBucket(iblockdata, world, blockposition, entityhuman, enumhand, itemstack, new ItemStack(Items.WATER_BUCKET), (iblockdata1) -> {
|
||||
return (Integer) iblockdata1.getValue(LayeredCauldronBlock.LEVEL) == 3;
|
||||
- }, SoundEvents.BUCKET_FILL);
|
||||
+ }, SoundEvents.BUCKET_FILL, hitDirection); // Paper - add hitDirection
|
||||
});
|
||||
- map1.put(Items.GLASS_BOTTLE, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
+ map1.put(Items.GLASS_BOTTLE, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
if (!world.isClientSide) {
|
||||
// CraftBukkit start
|
||||
if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_FILL)) {
|
||||
@@ -127,7 +127,7 @@ public interface CauldronInteraction {
|
||||
|
||||
return ItemInteractionResult.sidedSuccess(world.isClientSide);
|
||||
});
|
||||
- map1.put(Items.POTION, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
+ map1.put(Items.POTION, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
if ((Integer) iblockdata.getValue(LayeredCauldronBlock.LEVEL) == 3) {
|
||||
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
|
||||
} else {
|
||||
@@ -194,15 +194,15 @@ public interface CauldronInteraction {
|
||||
map1.put(Items.YELLOW_SHULKER_BOX, CauldronInteraction.SHULKER_BOX);
|
||||
Map<Item, CauldronInteraction> map2 = CauldronInteraction.LAVA.map();
|
||||
|
||||
- map2.put(Items.BUCKET, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
+ map2.put(Items.BUCKET, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
return CauldronInteraction.fillBucket(iblockdata, world, blockposition, entityhuman, enumhand, itemstack, new ItemStack(Items.LAVA_BUCKET), (iblockdata1) -> {
|
||||
return true;
|
||||
- }, SoundEvents.BUCKET_FILL_LAVA);
|
||||
+ }, SoundEvents.BUCKET_FILL_LAVA, hitDirection); // Paper - add hitDirection
|
||||
});
|
||||
CauldronInteraction.addDefaultInteractions(map2);
|
||||
Map<Item, CauldronInteraction> map3 = CauldronInteraction.POWDER_SNOW.map();
|
||||
|
||||
- map3.put(Items.BUCKET, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
+ map3.put(Items.BUCKET, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
return CauldronInteraction.fillBucket(iblockdata, world, blockposition, entityhuman, enumhand, itemstack, new ItemStack(Items.POWDER_SNOW_BUCKET), (iblockdata1) -> {
|
||||
return (Integer) iblockdata1.getValue(LayeredCauldronBlock.LEVEL) == 3;
|
||||
}, SoundEvents.BUCKET_FILL_POWDER_SNOW);
|
||||
@@ -217,10 +217,24 @@ public interface CauldronInteraction {
|
||||
}
|
||||
|
||||
static ItemInteractionResult fillBucket(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, ItemStack output, Predicate<BlockState> fullPredicate, SoundEvent soundEvent) {
|
||||
+ // Paper start - add hitDirection
|
||||
+ return fillBucket(state, world, pos, player, hand, stack, output, fullPredicate, soundEvent, null); // Paper - add hitDirection
|
||||
+ }
|
||||
+ static ItemInteractionResult fillBucket(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, ItemStack output, Predicate<BlockState> fullPredicate, SoundEvent soundEvent, @javax.annotation.Nullable net.minecraft.core.Direction hitDirection) {
|
||||
+ // Paper end - add hitDirection
|
||||
if (!fullPredicate.test(state)) {
|
||||
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
|
||||
} else {
|
||||
if (!world.isClientSide) {
|
||||
+ // Paper start - fire PlayerBucketFillEvent
|
||||
+ if (hitDirection != null) {
|
||||
+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketFillEvent((net.minecraft.server.level.ServerLevel) world, player, pos, pos, hitDirection, stack, output.getItem(), hand);
|
||||
+ if (event.isCancelled()) {
|
||||
+ return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
|
||||
+ }
|
||||
+ output = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY;
|
||||
+ }
|
||||
+ // Paper end - fire PlayerBucketFillEvent
|
||||
// CraftBukkit start
|
||||
if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL, false)) { // Paper - Call CauldronLevelChangeEvent
|
||||
return ItemInteractionResult.SUCCESS;
|
||||
@@ -241,7 +255,22 @@ public interface CauldronInteraction {
|
||||
}
|
||||
|
||||
static ItemInteractionResult emptyBucket(Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, BlockState state, SoundEvent soundEvent) {
|
||||
+ // Paper start - add hitDirection
|
||||
+ return emptyBucket(world, pos, player, hand, stack, state, soundEvent, null);
|
||||
+ }
|
||||
+ static ItemInteractionResult emptyBucket(Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, BlockState state, SoundEvent soundEvent, @javax.annotation.Nullable net.minecraft.core.Direction hitDirection) {
|
||||
+ // Paper end - add hitDirection
|
||||
if (!world.isClientSide) {
|
||||
+ // Paper start - fire PlayerBucketEmptyEvent
|
||||
+ ItemStack output = new ItemStack(Items.BUCKET);
|
||||
+ if (hitDirection != null) {
|
||||
+ org.bukkit.event.player.PlayerBucketEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBucketEmptyEvent((net.minecraft.server.level.ServerLevel) world, player, pos, pos, hitDirection, stack, hand);
|
||||
+ if (event.isCancelled()) {
|
||||
+ return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
|
||||
+ }
|
||||
+ output = event.getItemStack() != null ? org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItemStack()) : ItemStack.EMPTY;
|
||||
+ }
|
||||
+ // Paper end - fire PlayerBucketEmptyEvent
|
||||
// CraftBukkit start
|
||||
if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY, false)) { // Paper - Call CauldronLevelChangeEvent
|
||||
return ItemInteractionResult.SUCCESS;
|
||||
@@ -249,7 +278,7 @@ public interface CauldronInteraction {
|
||||
// CraftBukkit end
|
||||
Item item = stack.getItem();
|
||||
|
||||
- player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, new ItemStack(Items.BUCKET)));
|
||||
+ player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, output)); // Paper
|
||||
player.awardStat(Stats.FILL_CAULDRON);
|
||||
player.awardStat(Stats.ITEM_USED.get(item));
|
||||
// world.setBlockAndUpdate(blockposition, iblockdata); // CraftBukkit
|
||||
@@ -267,16 +296,16 @@ public interface CauldronInteraction {
|
||||
CauldronInteraction.InteractionMap WATER = CauldronInteraction.newInteractionMap("water");
|
||||
CauldronInteraction.InteractionMap LAVA = CauldronInteraction.newInteractionMap("lava");
|
||||
CauldronInteraction.InteractionMap POWDER_SNOW = CauldronInteraction.newInteractionMap("powder_snow");
|
||||
- CauldronInteraction FILL_WATER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
- return CauldronInteraction.emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, (BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY);
|
||||
+ CauldronInteraction FILL_WATER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
+ return CauldronInteraction.emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, (BlockState) Blocks.WATER_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY, hitDirection); // Paper - add hitDirection
|
||||
};
|
||||
- CauldronInteraction FILL_LAVA = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
- return CauldronInteraction.emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA);
|
||||
+ CauldronInteraction FILL_LAVA = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
+ return CauldronInteraction.emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, Blocks.LAVA_CAULDRON.defaultBlockState(), SoundEvents.BUCKET_EMPTY_LAVA, hitDirection); // Paper - add hitDirection
|
||||
};
|
||||
- CauldronInteraction FILL_POWDER_SNOW = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
+ CauldronInteraction FILL_POWDER_SNOW = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
return CauldronInteraction.emptyBucket(world, blockposition, entityhuman, enumhand, itemstack, (BlockState) Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY_POWDER_SNOW);
|
||||
};
|
||||
- CauldronInteraction SHULKER_BOX = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
|
||||
+ CauldronInteraction SHULKER_BOX = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // Paper - add hitDirection
|
||||
// CraftBukkit end
|
||||
Block block = Block.byItem(itemstack.getItem());
|
||||
|
||||
@@ -299,7 +328,7 @@ public interface CauldronInteraction {
|
||||
return ItemInteractionResult.sidedSuccess(world.isClientSide);
|
||||
}
|
||||
};
|
||||
- CauldronInteraction BANNER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> { // CraftBukkit - decompile error
|
||||
+ CauldronInteraction BANNER = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // CraftBukkit - decompile error // Paper - add hitDirection
|
||||
BannerPatternLayers bannerpatternlayers = (BannerPatternLayers) itemstack.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY);
|
||||
|
||||
if (bannerpatternlayers.layers().isEmpty()) {
|
||||
@@ -322,7 +351,7 @@ public interface CauldronInteraction {
|
||||
return ItemInteractionResult.sidedSuccess(world.isClientSide);
|
||||
}
|
||||
};
|
||||
- CauldronInteraction DYED_ITEM = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> { // CraftBukkit - decompile error
|
||||
+ CauldronInteraction DYED_ITEM = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack, hitDirection) -> { // CraftBukkit - decompile error // Paper - add hitDirection
|
||||
if (!itemstack.is(ItemTags.DYEABLE)) {
|
||||
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
|
||||
} else if (!itemstack.has(DataComponents.DYED_COLOR)) {
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/AbstractCauldronBlock.java b/src/main/java/net/minecraft/world/level/block/AbstractCauldronBlock.java
|
||||
index 20f2b575c8131621edea0e75fbf38a9fe20a36c4..4fdef6d7bcea0cf6b7d90324398af597660c80e3 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/AbstractCauldronBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/AbstractCauldronBlock.java
|
||||
@@ -58,7 +58,7 @@ public abstract class AbstractCauldronBlock extends Block {
|
||||
ItemStack stack, BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit
|
||||
) {
|
||||
CauldronInteraction cauldronInteraction = this.interactions.map().get(stack.getItem());
|
||||
- return cauldronInteraction.interact(state, world, pos, player, hand, stack);
|
||||
+ return cauldronInteraction.interact(state, world, pos, player, hand, stack, hit.getDirection()); // Paper - pass hit direction
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,36 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Mariell Hoversholm <proximyst@proximyst.com>
|
||||
Date: Sun, 29 Sep 2024 16:21:26 +0200
|
||||
Subject: [PATCH] Add PlayerInsertLecternBookEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/LecternBlock.java b/src/main/java/net/minecraft/world/level/block/LecternBlock.java
|
||||
index ebb79907391fe3128d3d16fbe9d8cb0b22bcc9f7..3a1e2f62b297f384cc0dcfb828e523a37c703d6f 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/LecternBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/LecternBlock.java
|
||||
@@ -157,7 +157,24 @@ public class LecternBlock extends BaseEntityBlock {
|
||||
BlockEntity tileentity = world.getBlockEntity(pos);
|
||||
|
||||
if (tileentity instanceof LecternBlockEntity tileentitylectern) {
|
||||
- tileentitylectern.setBook(stack.consumeAndReturn(1, user));
|
||||
+ // Paper start - Add PlayerInsertLecternBookEvent
|
||||
+ ItemStack eventSourcedBookStack = null;
|
||||
+ if (user instanceof final net.minecraft.server.level.ServerPlayer serverPlayer) {
|
||||
+ final io.papermc.paper.event.player.PlayerInsertLecternBookEvent event = new io.papermc.paper.event.player.PlayerInsertLecternBookEvent(
|
||||
+ serverPlayer.getBukkitEntity(),
|
||||
+ org.bukkit.craftbukkit.block.CraftBlock.at(world, pos),
|
||||
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack.copyWithCount(1))
|
||||
+ );
|
||||
+ if (!event.callEvent()) return;
|
||||
+ eventSourcedBookStack = org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getBook());
|
||||
+ }
|
||||
+ if (eventSourcedBookStack == null) {
|
||||
+ eventSourcedBookStack = stack.consumeAndReturn(1, user);
|
||||
+ } else {
|
||||
+ stack.consume(1, user);
|
||||
+ }
|
||||
+ tileentitylectern.setBook(eventSourcedBookStack);
|
||||
+ // Paper end - Add PlayerInsertLecternBookEvent
|
||||
LecternBlock.resetBookState(user, world, pos, state, true);
|
||||
world.playSound((Player) null, pos, SoundEvents.BOOK_PUT, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Axionize <154778082+Axionize@users.noreply.github.com>
|
||||
Date: Sun, 29 Sep 2024 14:20:42 -0700
|
||||
Subject: [PATCH] Void damage configuration API
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index bc45c74987974b4828201e06fc8b1f3fbc0af8b4..4b54d0ea31062972e68ee8fafe3cfaf68f65a5cd 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -931,8 +931,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public void checkBelowWorld() {
|
||||
+ if (!this.level.getWorld().isVoidDamageEnabled()) return; // Paper - check if void damage is enabled on the world
|
||||
+
|
||||
// Paper start - Configurable nether ceiling damage
|
||||
- if (this.getY() < (double) (this.level.getMinBuildHeight() - 64) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER
|
||||
+ if (this.getY() < (double) (this.level.getMinBuildHeight() + this.level.getWorld().getVoidDamageMinBuildHeightOffset()) || (this.level.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER // Paper - use configured min build height offset
|
||||
&& this.level.paperConfig().environment.netherCeilingVoidDamageHeight.test(v -> this.getY() >= v)
|
||||
&& (!(this instanceof Player player) || !player.getAbilities().invulnerable))) {
|
||||
// Paper end - Configurable nether ceiling damage
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 30f4f1254fc295442d72d50479e8af635f2fe983..2aa6374cd4a96efd85899be8cd3172a8257bfe6b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -2625,7 +2625,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
|
||||
@Override
|
||||
protected void onBelowWorld() {
|
||||
- this.hurt(this.damageSources().fellOutOfWorld(), 4.0F);
|
||||
+ this.hurt(this.damageSources().fellOutOfWorld(), this.level().getWorld().getVoidDamageAmount()); // Paper - use configured void damage amount
|
||||
}
|
||||
|
||||
protected void updateSwingTime() {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 38b046da5acac8633db8618a2957187d291f5e73..33e4818ba5a90d78d69baad9f6b1be1b1382e9f3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -163,6 +163,41 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
private final Object2IntOpenHashMap<SpawnCategory> spawnCategoryLimit = new Object2IntOpenHashMap<>();
|
||||
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftWorld.DATA_TYPE_REGISTRY);
|
||||
private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
|
||||
+ // Paper start - void damage configuration
|
||||
+ private boolean voidDamageEnabled;
|
||||
+ private float voidDamageAmount;
|
||||
+ private double voidDamageMinBuildHeightOffset;
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isVoidDamageEnabled() {
|
||||
+ return this.voidDamageEnabled;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setVoidDamageEnabled(final boolean enabled) {
|
||||
+ this.voidDamageEnabled = enabled;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public float getVoidDamageAmount() {
|
||||
+ return this.voidDamageAmount;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setVoidDamageAmount(float voidDamageAmount) {
|
||||
+ this.voidDamageAmount = voidDamageAmount;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public double getVoidDamageMinBuildHeightOffset() {
|
||||
+ return this.voidDamageMinBuildHeightOffset;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setVoidDamageMinBuildHeightOffset(double minBuildHeightOffset) {
|
||||
+ this.voidDamageMinBuildHeightOffset = minBuildHeightOffset;
|
||||
+ }
|
||||
+ // Paper end - void damage configuration
|
||||
|
||||
// Paper start - Provide fast information methods
|
||||
@Override
|
||||
@@ -271,6 +306,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
}
|
||||
}
|
||||
// Paper end - per world spawn limits
|
||||
+
|
||||
+ // Paper start - per world void damage height
|
||||
+ this.voidDamageEnabled = this.world.paperConfig().environment.voidDamageAmount.enabled();
|
||||
+ this.voidDamageMinBuildHeightOffset = this.world.paperConfig().environment.voidDamageMinBuildHeightOffset;
|
||||
+ this.voidDamageAmount = (float) this.world.paperConfig().environment.voidDamageAmount.or(0);
|
||||
+ // Paper end - per world void damage height
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,45 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
|
||||
Date: Sat, 9 Jul 2022 17:28:42 +0200
|
||||
Subject: [PATCH] Add Offline PDC API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
index 4f4e3ee18d586f61706504218cddc06a38ca5580..94ca0407303c4493ab4928b12ec6ecc75aaca549 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
|
||||
@@ -325,6 +325,34 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+ // Paper start - Add Offline PDC API
|
||||
+ private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
||||
+ private io.papermc.paper.persistence.@org.checkerframework.checker.nullness.qual.MonotonicNonNull PersistentDataContainerView persistentDataContainerView;
|
||||
+
|
||||
+ @Override
|
||||
+ public io.papermc.paper.persistence.PersistentDataContainerView getPersistentDataContainer() {
|
||||
+ if (this.persistentDataContainerView == null) {
|
||||
+ this.persistentDataContainerView = new io.papermc.paper.persistence.PaperPersistentDataContainerView(DATA_TYPE_REGISTRY) {
|
||||
+
|
||||
+ private CompoundTag getPersistentTag() {
|
||||
+ return net.minecraft.Optionull.map(CraftOfflinePlayer.this.getData(), data -> data.getCompound("BukkitValues"));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public CompoundTag toTagCompound() {
|
||||
+ return java.util.Objects.requireNonNullElseGet(this.getPersistentTag(), CompoundTag::new);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public net.minecraft.nbt.Tag getTag(String key) {
|
||||
+ return net.minecraft.Optionull.map(this.getPersistentTag(), tag -> tag.get(key));
|
||||
+ }
|
||||
+ };
|
||||
+ }
|
||||
+ return this.persistentDataContainerView;
|
||||
+ }
|
||||
+ // Paper end - Add Offline PDC API
|
||||
+
|
||||
@Override
|
||||
public Location getLastDeathLocation() {
|
||||
if (this.getData().contains("LastDeathLocation", 10)) {
|
|
@ -1,53 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Doc <nachito94@msn.com>
|
||||
Date: Sun, 6 Oct 2024 16:46:36 -0300
|
||||
Subject: [PATCH] Add AnvilView#bypassEnchantmentLevelRestriction
|
||||
|
||||
Anvils, by default, limit applied enchantment levels to their respective
|
||||
maximum level. The added API enables plugins to disable this behaviour,
|
||||
allowing enchantments that are overleveled to be applied via the anvil.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
||||
index d685511104ac552dfc9ae2111e1bfb60fa812102..362278407679f245ebcea778f2199b357339e1fe 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/AnvilMenu.java
|
||||
@@ -53,6 +53,7 @@ public class AnvilMenu extends ItemCombinerMenu {
|
||||
public int maximumRepairCost = 40;
|
||||
private CraftAnvilView bukkitEntity;
|
||||
// CraftBukkit end
|
||||
+ public boolean bypassEnchantmentLevelRestriction = false; // Paper - bypass anvil level restrictions
|
||||
|
||||
public AnvilMenu(int syncId, Inventory inventory) {
|
||||
this(syncId, inventory, ContainerLevelAccess.NULL);
|
||||
@@ -231,7 +232,7 @@ public class AnvilMenu extends ItemCombinerMenu {
|
||||
flag2 = true;
|
||||
} else {
|
||||
flag1 = true;
|
||||
- if (i2 > enchantment.getMaxLevel()) {
|
||||
+ if (i2 > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions
|
||||
i2 = enchantment.getMaxLevel();
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java
|
||||
index fdc2bd4c3ee5f762a72df39c87215e3a15f47db2..f86c95a13dff012de5db3e41ac261e9e8d44d9f3 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java
|
||||
@@ -50,6 +50,18 @@ public class CraftAnvilView extends CraftInventoryView<AnvilMenu, AnvilInventory
|
||||
this.container.maximumRepairCost = cost;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean bypassesEnchantmentLevelRestriction() {
|
||||
+ return this.container.bypassEnchantmentLevelRestriction;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void bypassEnchantmentLevelRestriction(final boolean bypassEnchantmentLevelRestriction) {
|
||||
+ this.container.bypassEnchantmentLevelRestriction = bypassEnchantmentLevelRestriction;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public void updateFromLegacy(CraftInventoryAnvil legacy) {
|
||||
if (legacy.isRepairCostSet()) {
|
||||
this.setRepairCost(legacy.getRepairCost());
|
|
@ -1,168 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Wed, 16 Oct 2024 06:41:32 -0700
|
||||
Subject: [PATCH] Add proper async player disconnections
|
||||
|
||||
Blocking can cause performance problems
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
||||
index 3e550f8e7cd4f4e16f499a8a2a4b95420270f07a..4a8356a714ed50d4a32bcf046a2e16491bef014b 100644
|
||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
||||
@@ -850,6 +850,14 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start - add proper async disconnect
|
||||
+ public void enableAutoRead() {
|
||||
+ if (this.channel != null) {
|
||||
+ this.channel.config().setAutoRead(true);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - add proper async disconnect
|
||||
+
|
||||
public void setupCompression(int compressionThreshold, boolean rejectsBadPackets) {
|
||||
if (compressionThreshold >= 0) {
|
||||
com.velocitypowered.natives.compression.VelocityCompressor compressor = com.velocitypowered.natives.util.Natives.compress.get().create(io.papermc.paper.configuration.GlobalConfiguration.get().misc.compressionLevel.or(-1)); // Paper - Use Velocity cipher
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index 6998f32f8d79dbdb6b31ffaa126602fc4a428616..7174f8c89a7cdcf40ff28f6636ecfb23b13ccdaa 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
@@ -136,11 +136,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
this.latency = (this.latency * 3 + i) / 4;
|
||||
this.keepAlivePending = false;
|
||||
} else if (!this.isSingleplayerOwner()) {
|
||||
- // Paper start - This needs to be handled on the main thread for plugins
|
||||
- server.submit(() -> {
|
||||
- this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - kick event cause
|
||||
- });
|
||||
- // Paper end - This needs to be handled on the main thread for plugins
|
||||
+ this.disconnectAsync(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE, PlayerKickEvent.Cause.TIMEOUT); // Paper - add proper async disconnect
|
||||
}
|
||||
|
||||
}
|
||||
@@ -404,6 +400,31 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
minecraftserver.scheduleOnMain(networkmanager::handleDisconnection); // Paper
|
||||
}
|
||||
|
||||
+ // Paper start - add proper async disconnect
|
||||
+ public void disconnectAsync(net.kyori.adventure.text.Component reason, PlayerKickEvent.Cause cause) {
|
||||
+ this.disconnectAsync(io.papermc.paper.adventure.PaperAdventure.asVanilla(reason), cause);
|
||||
+ }
|
||||
+
|
||||
+ public void disconnectAsync(Component reason, PlayerKickEvent.Cause cause) {
|
||||
+ this.disconnectAsync(new DisconnectionDetails(reason), cause);
|
||||
+ }
|
||||
+
|
||||
+ public void disconnectAsync(DisconnectionDetails disconnectionInfo, PlayerKickEvent.Cause cause) {
|
||||
+ if (this.cserver.isPrimaryThread()) {
|
||||
+ this.disconnect(disconnectionInfo, cause);
|
||||
+ return;
|
||||
+ }
|
||||
+ this.connection.setReadOnly();
|
||||
+ this.server.scheduleOnMain(() -> {
|
||||
+ ServerCommonPacketListenerImpl.this.disconnect(disconnectionInfo, cause);
|
||||
+ if (ServerCommonPacketListenerImpl.this.player.quitReason == null) {
|
||||
+ // cancelled
|
||||
+ ServerCommonPacketListenerImpl.this.connection.enableAutoRead();
|
||||
+ }
|
||||
+ });
|
||||
+ }
|
||||
+ // Paper end - add proper async disconnect
|
||||
+
|
||||
protected boolean isSingleplayerOwner() {
|
||||
return this.server.isSingleplayerOwner(this.playerProfile());
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index befeaac4786760f6847a5945da2296a3e68dbb17..064d52d4479727c6a32bf357be8da32d1760e7fc 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -791,7 +791,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
// PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper - AsyncTabCompleteEvent; run this async
|
||||
// CraftBukkit start
|
||||
if (this.chatSpamTickCount.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.tabSpamLimit && !this.server.getPlayerList().isOp(this.player.getGameProfile())) { // Paper - configurable tab spam limits
|
||||
- this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause
|
||||
+ this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause // Paper - add proper async disconnect
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@@ -803,7 +803,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
// Paper start
|
||||
final int index;
|
||||
if (packet.getCommand().length() > 64 && ((index = packet.getCommand().indexOf(' ')) == -1 || index >= 64)) {
|
||||
- this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM);
|
||||
+ this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - add proper async disconnect
|
||||
return;
|
||||
}
|
||||
// Paper end
|
||||
@@ -1190,14 +1190,14 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
if (byteTotal > byteAllowed) {
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("{} tried to send a book too large. Book size: {} - Allowed: {} - Pages: {}", this.player.getScoreboardName(), byteTotal, byteAllowed, pageList.size());
|
||||
- this.disconnect(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause
|
||||
+ this.disconnectAsync(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause // Paper - add proper async disconnect
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Paper end - Book size limits
|
||||
// CraftBukkit start
|
||||
if (this.lastBookTick + 20 > MinecraftServer.currentTick) {
|
||||
- this.disconnect(Component.literal("Book edited too quickly!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause
|
||||
+ this.disconnectAsync(Component.literal("Book edited too quickly!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause // Paper - add proper async disconnect
|
||||
return;
|
||||
}
|
||||
this.lastBookTick = MinecraftServer.currentTick;
|
||||
@@ -2354,7 +2354,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
private void tryHandleChat(String s, Runnable runnable, boolean sync) { // CraftBukkit
|
||||
if (ServerGamePacketListenerImpl.isChatMessageIllegal(s)) {
|
||||
- this.disconnect((Component) Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper
|
||||
+ this.disconnectAsync((Component) Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper // Paper - add proper async disconnect
|
||||
} else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales
|
||||
this.send(new ClientboundSystemChatPacket(Component.translatable("chat.disabled.options").withStyle(ChatFormatting.RED), false));
|
||||
} else {
|
||||
@@ -2377,7 +2377,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
|
||||
if (optional.isEmpty()) {
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString());
|
||||
- this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes
|
||||
+ this.disconnectAsync(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes // Paper - add proper async disconnect
|
||||
}
|
||||
|
||||
return optional;
|
||||
@@ -2550,7 +2550,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
// this.chatSpamTickCount += 20;
|
||||
if (counted && this.chatSpamTickCount.addAndGet(20) > 200 && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { // Paper - exclude from SpigotConfig.spamExclusions
|
||||
// CraftBukkit end
|
||||
- this.disconnect((Component) Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause
|
||||
+ this.disconnectAsync((Component) Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause // Paper - add proper async disconnect
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2562,7 +2562,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
synchronized (this.lastSeenMessages) {
|
||||
if (!this.lastSeenMessages.applyOffset(packet.offset())) {
|
||||
ServerGamePacketListenerImpl.LOGGER.warn("Failed to validate message acknowledgements from {}", this.player.getName().getString());
|
||||
- this.disconnect(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes
|
||||
+ this.disconnectAsync(ServerGamePacketListenerImpl.CHAT_VALIDATION_FAILED, org.bukkit.event.player.PlayerKickEvent.Cause.CHAT_VALIDATION_FAILED); // Paper - kick event causes // Paper - add proper async disconnect
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2710,7 +2710,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
}
|
||||
|
||||
if (i > 4096) {
|
||||
- this.disconnect((Component) Component.translatable("multiplayer.disconnect.too_many_pending_chats"), org.bukkit.event.player.PlayerKickEvent.Cause.TOO_MANY_PENDING_CHATS); // Paper - kick event cause
|
||||
+ this.disconnectAsync((Component) Component.translatable("multiplayer.disconnect.too_many_pending_chats"), org.bukkit.event.player.PlayerKickEvent.Cause.TOO_MANY_PENDING_CHATS); // Paper - kick event cause // Paper - add proper async disconnect
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3314,7 +3314,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
// Paper start - auto recipe limit
|
||||
if (!org.bukkit.Bukkit.isPrimaryThread()) {
|
||||
if (this.recipeSpamPackets.addAndGet(io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamIncrement) > io.papermc.paper.configuration.GlobalConfiguration.get().spamLimiter.recipeSpamLimit) {
|
||||
- this.disconnect(net.minecraft.network.chat.Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause
|
||||
+ this.disconnectAsync(net.minecraft.network.chat.Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause // Paper - add proper async disconnect
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 20 Oct 2024 18:23:59 +0100
|
||||
Subject: [PATCH] Always send Banner patterns to the client
|
||||
|
||||
The mojang client will not remove patterns from a Banner when none
|
||||
are sent inside of an update packet, given that this is not an expected
|
||||
flow for them, this is not all too surprising. So, we shall resort to always
|
||||
sending the patterns over the network for update packets.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
|
||||
index 60c26076e7acf869fa0e20fdc14eeec341387d99..60a9f3c7f007d268f24a4fe9e87029fdbc8360f9 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/BannerBlockEntity.java
|
||||
@@ -63,7 +63,7 @@ public class BannerBlockEntity extends BlockEntity implements Nameable {
|
||||
@Override
|
||||
protected void saveAdditional(CompoundTag nbt, HolderLookup.Provider registryLookup) {
|
||||
super.saveAdditional(nbt, registryLookup);
|
||||
- if (!this.patterns.equals(BannerPatternLayers.EMPTY)) {
|
||||
+ if (!this.patterns.equals(BannerPatternLayers.EMPTY) || serialisingForNetwork.get()) { // Paper - always send patterns to client
|
||||
nbt.put("patterns", (Tag) BannerPatternLayers.CODEC.encodeStart(registryLookup.createSerializationContext(NbtOps.INSTANCE), this.patterns).getOrThrow());
|
||||
}
|
||||
|
||||
@@ -95,9 +95,18 @@ public class BannerBlockEntity extends BlockEntity implements Nameable {
|
||||
return ClientboundBlockEntityDataPacket.create(this);
|
||||
}
|
||||
|
||||
+ // Paper start - always send patterns to client
|
||||
+ ThreadLocal<Boolean> serialisingForNetwork = ThreadLocal.withInitial(() -> Boolean.FALSE);
|
||||
@Override
|
||||
public CompoundTag getUpdateTag(HolderLookup.Provider registryLookup) {
|
||||
- return this.saveWithoutMetadata(registryLookup);
|
||||
+ final Boolean wasSerialisingForNetwork = serialisingForNetwork.get();
|
||||
+ try {
|
||||
+ serialisingForNetwork.set(Boolean.TRUE);
|
||||
+ return this.saveWithoutMetadata(registryLookup);
|
||||
+ } finally {
|
||||
+ serialisingForNetwork.set(wasSerialisingForNetwork);
|
||||
+ }
|
||||
+ // Paper end - always send patterns to client
|
||||
}
|
||||
|
||||
public BannerPatternLayers getPatterns() {
|
Loading…
Add table
Add a link
Reference in a new issue