From 66779f5c86c979f81f7f7076f715c7d966f6a5f1 Mon Sep 17 00:00:00 2001 From: Riley Park Date: Fri, 29 Jan 2021 17:54:03 +0100 Subject: [PATCH] Adventure == AT == public net.minecraft.network.chat.HoverEvent$ItemStackInfo item public net.minecraft.network.chat.HoverEvent$ItemStackInfo count public net.minecraft.network.chat.HoverEvent$ItemStackInfo components public net.minecraft.network.chat.contents.TranslatableContents filterAllowedArguments(Ljava/lang/Object;)Lcom/mojang/serialization/DataResult; Co-authored-by: zml Co-authored-by: Jake Potrebic --- .../net/minecraft/ChatFormatting.java.patch | 21 + .../commands/CommandSourceStack.java.patch | 18 +- .../arguments/MessageArgument.java.patch | 29 + .../selector/EntitySelector.java.patch | 2 +- .../network/FriendlyByteBuf.java.patch | 48 +- .../network/PacketEncoder.java.patch | 15 +- .../network/chat/ChatDecorator.java.patch | 23 + .../chat/ComponentSerialization.java.patch | 99 ++++ .../network/chat/ComponentUtils.java.patch | 14 + .../network/chat/MessageSignature.java.patch | 10 + .../network/chat/MutableComponent.java.patch | 14 + .../chat/OutgoingChatMessage.java.patch | 44 ++ .../network/chat/PlayerChatMessage.java.patch | 61 +++ .../ClientboundSystemChatPacket.java.patch | 7 +- ...lientboundLoginDisconnectPacket.java.patch | 21 + .../server/MinecraftServer.java.patch | 144 +++-- .../server/level/ServerPlayer.java.patch | 187 ++++--- .../ServerCommonPacketListenerImpl.java.patch | 59 +- ...ConfigurationPacketListenerImpl.java.patch | 10 +- .../ServerGamePacketListenerImpl.java.patch | 195 ++++--- .../ServerLoginPacketListenerImpl.java.patch | 6 +- .../ServerStatusPacketListenerImpl.java.patch | 2 +- .../server/players/PlayerList.java.patch | 130 +++-- .../net/minecraft/world/BossEvent.java.patch | 86 +++ .../minecraft/world/item/ItemStack.java.patch | 60 ++- .../block/entity/SignBlockEntity.java.patch | 10 +- .../maps/MapItemSavedData.java.patch | 23 +- .../paper/adventure/AdventureCodecs.java | 450 ++++++++++++++++ .../paper/adventure/AdventureComponent.java | 88 +++ .../adventure/BossBarImplementationImpl.java | 85 +++ .../paper/adventure/ChatProcessor.java | 376 +++++++++++++ .../papermc/paper/adventure/DisplayNames.java | 25 + .../adventure/ImprovedChatDecorator.java | 55 ++ .../paper/adventure/LazyChatAudienceSet.java | 26 + .../paper/adventure/PaperAdventure.java | 505 ++++++++++++++++++ .../adventure/WrapperAwareSerializer.java | 43 ++ .../BossBarImplementationProvider.java | 14 + .../providers/ClickCallbackProviderImpl.java | 96 ++++ .../ComponentLoggerProviderImpl.java | 20 + ...taComponentValueConverterProviderImpl.java | 82 +++ .../GsonComponentSerializerProviderImpl.java | 30 ++ ...LegacyComponentSerializerProviderImpl.java | 36 ++ .../providers/MiniMessageProviderImpl.java | 20 + .../NBTLegacyHoverEventSerializer.java | 91 ++++ ...inTextComponentSerializerProviderImpl.java | 23 + .../bukkit/craftbukkit/CraftJukeboxSong.java | 1 + .../org/bukkit/craftbukkit/CraftServer.java | 114 +++- .../bukkit/craftbukkit/CraftServerLinks.java | 20 + .../org/bukkit/craftbukkit/CraftWorld.java | 50 ++ .../java/org/bukkit/craftbukkit/Main.java | 6 + .../bukkit/craftbukkit/block/CraftBeacon.java | 13 + .../craftbukkit/block/CraftCommandBlock.java | 12 + .../craftbukkit/block/CraftContainer.java | 13 + .../block/CraftEnchantingTable.java | 13 + .../bukkit/craftbukkit/block/CraftSign.java | 31 ++ .../craftbukkit/block/sign/CraftSignSide.java | 70 ++- .../command/CraftBlockCommandSender.java | 12 + .../command/CraftConsoleCommandSender.java | 14 + .../CraftRemoteConsoleCommandSender.java | 7 + .../command/ProxiedNativeCommandSender.java | 7 + .../command/ServerCommandSender.java | 15 + .../enchantments/CraftEnchantment.java | 6 + .../craftbukkit/entity/CraftEntity.java | 38 ++ .../craftbukkit/entity/CraftHumanEntity.java | 15 +- .../entity/CraftMinecartCommand.java | 7 + .../craftbukkit/entity/CraftPlayer.java | 391 +++++++++++++- .../craftbukkit/entity/CraftTextDisplay.java | 11 + .../craftbukkit/event/CraftEventFactory.java | 4 +- .../craftbukkit/inventory/CraftContainer.java | 7 + .../inventory/CraftInventoryCustom.java | 39 ++ .../inventory/CraftInventoryView.java | 7 + .../inventory/CraftItemFactory.java | 17 + .../craftbukkit/inventory/CraftMenuType.java | 8 +- .../inventory/CraftMerchantCustom.java | 14 + .../craftbukkit/inventory/CraftMetaBook.java | 127 ++++- .../inventory/CraftMetaBookSigned.java | 109 +++- .../craftbukkit/inventory/CraftMetaItem.java | 38 +- .../inventory/CraftMetaPotion.java | 18 +- .../inventory/trim/CraftTrimMaterial.java | 8 + .../inventory/trim/CraftTrimPattern.java | 8 + .../util/CraftCustomInventoryConverter.java | 13 + .../inventory/util/CraftInventoryCreator.java | 16 + .../util/CraftTileInventoryConverter.java | 33 ++ .../craftbukkit/map/CraftMapRenderer.java | 2 +- .../scoreboard/CraftObjective.java | 15 + .../scoreboard/CraftScoreboard.java | 37 +- .../craftbukkit/scoreboard/CraftTeam.java | 73 +++ .../craftbukkit/util/CraftChatMessage.java | 3 +- .../craftbukkit/util/CraftMagicNumbers.java | 37 ++ .../bukkit/craftbukkit/util/LazyHashSet.java | 2 +- .../craftbukkit/util/LazyPlayerSet.java | 9 +- ...ure.bossbar.BossBarImplementation$Provider | 1 + ...dventure.text.event.ClickCallback$Provider | 1 + ...taComponentValueConverterRegistry$Provider | 1 + ....text.logger.slf4j.ComponentLoggerProvider | 1 + ...ture.text.minimessage.MiniMessage$Provider | 1 + ...izer.gson.GsonComponentSerializer$Provider | 1 + ....legacy.LegacyComponentSerializer$Provider | 1 + ...lain.PlainTextComponentSerializer$Provider | 1 + .../paper/data/paper/chat_type/raw.json | 14 + .../paper/adventure/AdventureCodecsTest.java | 405 ++++++++++++++ .../adventure/ComponentServicesTest.java | 25 + .../paper/util/MethodParameterSource.java | 2 + 103 files changed, 4975 insertions(+), 392 deletions(-) create mode 100644 paper-server/patches/sources/net/minecraft/ChatFormatting.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/commands/arguments/MessageArgument.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/network/chat/ChatDecorator.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/network/chat/ComponentSerialization.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/network/chat/ComponentUtils.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/network/chat/MessageSignature.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/network/chat/MutableComponent.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/network/chat/PlayerChatMessage.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/network/protocol/login/ClientboundLoginDisconnectPacket.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/BossEvent.java.patch create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/AdventureCodecs.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/AdventureComponent.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/BossBarImplementationImpl.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/ChatProcessor.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/DisplayNames.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/ImprovedChatDecorator.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/LazyChatAudienceSet.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/PaperAdventure.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/WrapperAwareSerializer.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/providers/BossBarImplementationProvider.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/providers/ClickCallbackProviderImpl.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/providers/ComponentLoggerProviderImpl.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/providers/DataComponentValueConverterProviderImpl.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/providers/GsonComponentSerializerProviderImpl.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/providers/LegacyComponentSerializerProviderImpl.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/providers/MiniMessageProviderImpl.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/providers/NBTLegacyHoverEventSerializer.java create mode 100644 paper-server/src/main/java/io/papermc/paper/adventure/providers/PlainTextComponentSerializerProviderImpl.java create mode 100644 paper-server/src/main/resources/META-INF/services/net.kyori.adventure.bossbar.BossBarImplementation$Provider create mode 100644 paper-server/src/main/resources/META-INF/services/net.kyori.adventure.text.event.ClickCallback$Provider create mode 100644 paper-server/src/main/resources/META-INF/services/net.kyori.adventure.text.event.DataComponentValueConverterRegistry$Provider create mode 100644 paper-server/src/main/resources/META-INF/services/net.kyori.adventure.text.logger.slf4j.ComponentLoggerProvider create mode 100644 paper-server/src/main/resources/META-INF/services/net.kyori.adventure.text.minimessage.MiniMessage$Provider create mode 100644 paper-server/src/main/resources/META-INF/services/net.kyori.adventure.text.serializer.gson.GsonComponentSerializer$Provider create mode 100644 paper-server/src/main/resources/META-INF/services/net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer$Provider create mode 100644 paper-server/src/main/resources/META-INF/services/net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer$Provider create mode 100644 paper-server/src/main/resources/data/minecraft/datapacks/paper/data/paper/chat_type/raw.json create mode 100644 paper-server/src/test/java/io/papermc/paper/adventure/AdventureCodecsTest.java create mode 100644 paper-server/src/test/java/io/papermc/paper/adventure/ComponentServicesTest.java diff --git a/paper-server/patches/sources/net/minecraft/ChatFormatting.java.patch b/paper-server/patches/sources/net/minecraft/ChatFormatting.java.patch new file mode 100644 index 0000000000..eb700c93b5 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/ChatFormatting.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/ChatFormatting.java ++++ b/net/minecraft/ChatFormatting.java +@@ -112,6 +112,18 @@ + return name == null ? null : FORMATTING_BY_NAME.get(cleanName(name)); + } + ++ // Paper start - add method to get by hex value ++ @Nullable public static ChatFormatting getByHexValue(int i) { ++ for (ChatFormatting value : values()) { ++ if (value.getColor() != null && value.getColor() == i) { ++ return value; ++ } ++ } ++ ++ return null; ++ } ++ // Paper end - add method to get by hex value ++ + @Nullable + public static ChatFormatting getById(int colorIndex) { + if (colorIndex < 0) { diff --git a/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch b/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch index 9333d94423..56d645a43a 100644 --- a/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch @@ -8,15 +8,16 @@ public class CommandSourceStack implements ExecutionCommandSource, SharedSuggestionProvider { -@@ -65,6 +66,7 @@ +@@ -65,6 +66,8 @@ private final Vec2 rotation; private final CommandSigningContext signingContext; private final TaskChainer chatMessageChainer; + public volatile CommandNode currentCommand; // CraftBukkit ++ public boolean bypassSelectorPermissions = false; // Paper - add bypass for selector permissions public CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity) { this(output, pos, rot, world, level, name, displayName, server, entity, false, CommandResultCallback.EMPTY, EntityAnchorArgument.Anchor.FEET, CommandSigningContext.ANONYMOUS, TaskChainer.immediate(server)); -@@ -171,8 +173,22 @@ +@@ -171,9 +174,23 @@ @Override public boolean hasPermission(int level) { @@ -28,18 +29,19 @@ + // CraftBukkit end + return this.permissionLevel >= level; -+ } -+ + } + + // 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); - } ++ } + // CraftBukkit end - ++ public Vec3 getPosition() { return this.worldPosition; -@@ -302,13 +318,13 @@ + } +@@ -302,13 +319,13 @@ while (iterator.hasNext()) { ServerPlayer entityplayer = (ServerPlayer) iterator.next(); @@ -55,7 +57,7 @@ this.server.sendSystemMessage(ichatmutablecomponent); } -@@ -400,4 +416,10 @@ +@@ -400,4 +417,10 @@ public boolean isSilent() { return this.silent; } diff --git a/paper-server/patches/sources/net/minecraft/commands/arguments/MessageArgument.java.patch b/paper-server/patches/sources/net/minecraft/commands/arguments/MessageArgument.java.patch new file mode 100644 index 0000000000..647293ea7e --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/commands/arguments/MessageArgument.java.patch @@ -0,0 +1,29 @@ +--- a/net/minecraft/commands/arguments/MessageArgument.java ++++ b/net/minecraft/commands/arguments/MessageArgument.java +@@ -54,17 +54,21 @@ + private static void resolveSignedMessage(Consumer callback, CommandSourceStack source, PlayerChatMessage message) { + MinecraftServer minecraftServer = source.getServer(); + CompletableFuture completableFuture = filterPlainText(source, message); +- Component component = minecraftServer.getChatDecorator().decorate(source.getPlayer(), message.decoratedContent()); +- source.getChatMessageChainer().append(completableFuture, filtered -> { +- PlayerChatMessage playerChatMessage2 = message.withUnsignedContent(component).filter(filtered.mask()); ++ // Paper start - support asynchronous chat decoration ++ CompletableFuture componentFuture = minecraftServer.getChatDecorator().decorate(source.getPlayer(), source, message.decoratedContent()); ++ source.getChatMessageChainer().append(CompletableFuture.allOf(completableFuture, componentFuture), filtered -> { ++ PlayerChatMessage playerChatMessage2 = message.withUnsignedContent(componentFuture.join()).filter(completableFuture.join().mask()); ++ // Paper end - support asynchronous chat decoration + callback.accept(playerChatMessage2); + }); + } + + private static void resolveDisguisedMessage(Consumer callback, CommandSourceStack source, PlayerChatMessage message) { + ChatDecorator chatDecorator = source.getServer().getChatDecorator(); +- Component component = chatDecorator.decorate(source.getPlayer(), message.decoratedContent()); +- callback.accept(message.withUnsignedContent(component)); ++ // Paper start - support asynchronous chat decoration ++ CompletableFuture componentFuture = chatDecorator.decorate(source.getPlayer(), source, message.decoratedContent()); ++ source.getChatMessageChainer().append(componentFuture, (result) -> callback.accept(message.withUnsignedContent(result))); ++ // Paper end - support asynchronous chat decoration + } + + private static CompletableFuture filterPlainText(CommandSourceStack source, PlayerChatMessage message) { diff --git a/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch b/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch index 2aa168b7b6..cb23767a27 100644 --- a/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/arguments/selector/EntitySelector.java.patch @@ -5,7 +5,7 @@ private void checkPermissions(CommandSourceStack source) throws CommandSyntaxException { - if (this.usesSelector && !source.hasPermission(2)) { -+ if (this.usesSelector && !source.hasPermission(2, "minecraft.command.selector")) { // CraftBukkit ++ if (!source.bypassSelectorPermissions && (this.usesSelector && !source.hasPermission(2, "minecraft.command.selector"))) { // CraftBukkit // Paper - add bypass for selector perms throw EntityArgument.ERROR_SELECTORS_NOT_ALLOWED.create(); } } diff --git a/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch b/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch index c3723c4d7f..c9d512f8d6 100644 --- a/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/FriendlyByteBuf.java.patch @@ -1,6 +1,40 @@ --- a/net/minecraft/network/FriendlyByteBuf.java +++ b/net/minecraft/network/FriendlyByteBuf.java -@@ -139,7 +139,7 @@ +@@ -72,6 +72,7 @@ + + public static final int DEFAULT_NBT_QUOTA = 2097152; + private final ByteBuf source; ++ @Nullable public final java.util.Locale adventure$locale; // Paper - track player's locale for server-side translations + public static final short MAX_STRING_LENGTH = Short.MAX_VALUE; + public static final int MAX_COMPONENT_STRING_LENGTH = 262144; + private static final int PUBLIC_KEY_SIZE = 256; +@@ -80,6 +81,7 @@ + private static final Gson GSON = new Gson(); + + public FriendlyByteBuf(ByteBuf parent) { ++ this.adventure$locale = PacketEncoder.ADVENTURE_LOCALE.get(); // Paper - track player's locale for server-side translations + this.source = parent; + } + +@@ -120,11 +122,16 @@ + } + + public void writeJsonWithCodec(Codec codec, T value) { ++ // Paper start - Adventure; add max length parameter ++ this.writeJsonWithCodec(codec, value, MAX_STRING_LENGTH); ++ } ++ public void writeJsonWithCodec(Codec codec, T value, int maxLength) { ++ // Paper end - Adventure; add max length parameter + DataResult dataresult = codec.encodeStart(JsonOps.INSTANCE, value); + + this.writeUtf(FriendlyByteBuf.GSON.toJson((JsonElement) dataresult.getOrThrow((s) -> { + return new EncoderException("Failed to encode: " + s + " " + String.valueOf(value)); +- }))); ++ })), maxLength); // Paper - Adventure; add max length parameter + } + + public static IntFunction limitValue(IntFunction applier, int max) { +@@ -139,7 +146,7 @@ public > C readCollection(IntFunction collectionFactory, StreamDecoder reader) { int i = this.readVarInt(); @@ -9,7 +43,7 @@ for (int j = 0; j < i; ++j) { c0.add(reader.decode(this)); -@@ -150,7 +150,7 @@ +@@ -150,7 +157,7 @@ public void writeCollection(Collection collection, StreamEncoder writer) { this.writeVarInt(collection.size()); @@ -18,7 +52,7 @@ while (iterator.hasNext()) { T t0 = iterator.next(); -@@ -177,12 +177,12 @@ +@@ -177,12 +184,12 @@ public void writeIntIdList(IntList list) { this.writeVarInt(list.size()); @@ -33,7 +67,7 @@ for (int j = 0; j < i; ++j) { K k0 = keyReader.decode(this); -@@ -216,7 +216,7 @@ +@@ -216,7 +223,7 @@ } public > void writeEnumSet(EnumSet enumSet, Class type) { @@ -42,7 +76,7 @@ BitSet bitset = new BitSet(ae.length); for (int i = 0; i < ae.length; ++i) { -@@ -227,7 +227,7 @@ +@@ -227,7 +234,7 @@ } public > EnumSet readEnumSet(Class type) { @@ -51,7 +85,7 @@ BitSet bitset = this.readFixedBitSet(ae.length); EnumSet enumset = EnumSet.noneOf(type); -@@ -498,7 +498,7 @@ +@@ -498,7 +505,7 @@ } public > T readEnum(Class enumClass) { @@ -60,7 +94,7 @@ } public FriendlyByteBuf writeEnum(Enum instance) { -@@ -565,7 +565,7 @@ +@@ -565,7 +572,7 @@ try { NbtIo.writeAnyTag((Tag) nbt, new ByteBufOutputStream(buf)); diff --git a/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch b/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch index 4768aeef12..70ac5522a3 100644 --- a/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/PacketEncoder.java.patch @@ -1,6 +1,19 @@ --- a/net/minecraft/network/PacketEncoder.java +++ b/net/minecraft/network/PacketEncoder.java -@@ -31,7 +31,7 @@ +@@ -17,10 +17,12 @@ + this.protocolInfo = state; + } + ++ static final ThreadLocal ADVENTURE_LOCALE = ThreadLocal.withInitial(() -> null); // Paper - adventure; set player's locale + protected void encode(ChannelHandlerContext channelHandlerContext, Packet packet, ByteBuf byteBuf) throws Exception { + PacketType> packetType = packet.type(); + + try { ++ ADVENTURE_LOCALE.set(channelHandlerContext.channel().attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).get()); // Paper - adventure; set player's locale + this.protocolInfo.codec().encode(byteBuf, packet); + int i = byteBuf.readableBytes(); + if (LOGGER.isDebugEnabled()) { +@@ -31,7 +33,7 @@ JvmProfiler.INSTANCE.onPacketSent(this.protocolInfo.id(), packetType, channelHandlerContext.channel().remoteAddress(), i); } catch (Throwable var9) { diff --git a/paper-server/patches/sources/net/minecraft/network/chat/ChatDecorator.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/ChatDecorator.java.patch new file mode 100644 index 0000000000..8fe79b8a75 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/network/chat/ChatDecorator.java.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/network/chat/ChatDecorator.java ++++ b/net/minecraft/network/chat/ChatDecorator.java +@@ -2,10 +2,18 @@ + + import javax.annotation.Nullable; + import net.minecraft.server.level.ServerPlayer; ++import java.util.concurrent.CompletableFuture; // Paper + + @FunctionalInterface + public interface ChatDecorator { +- ChatDecorator PLAIN = (sender, message) -> message; ++ ChatDecorator PLAIN = (sender, message) -> CompletableFuture.completedFuture(message); // Paper - adventure; support async chat decoration events + +- Component decorate(@Nullable ServerPlayer sender, Component message); ++ @io.papermc.paper.annotation.DoNotUse @Deprecated // Paper - adventure; support chat decoration events (callers should use the overload with CommandSourceStack) ++ CompletableFuture decorate(@Nullable ServerPlayer sender, Component message); // Paper - adventure; support async chat decoration events ++ ++ // Paper start - adventure; support async chat decoration events ++ default CompletableFuture decorate(@Nullable ServerPlayer sender, @Nullable net.minecraft.commands.CommandSourceStack commandSourceStack, Component message) { ++ throw new UnsupportedOperationException("Must override this implementation"); ++ } ++ // Paper end - adventure; support async chat decoration events + } diff --git a/paper-server/patches/sources/net/minecraft/network/chat/ComponentSerialization.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/ComponentSerialization.java.patch new file mode 100644 index 0000000000..4136889ef4 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/network/chat/ComponentSerialization.java.patch @@ -0,0 +1,99 @@ +--- a/net/minecraft/network/chat/ComponentSerialization.java ++++ b/net/minecraft/network/chat/ComponentSerialization.java +@@ -37,9 +37,31 @@ + + public class ComponentSerialization { + public static final Codec CODEC = Codec.recursive("Component", ComponentSerialization::createCodec); +- public static final StreamCodec STREAM_CODEC = ByteBufCodecs.fromCodecWithRegistries(CODEC); ++ public static final StreamCodec STREAM_CODEC = createTranslationAware(() -> net.minecraft.nbt.NbtAccounter.create(net.minecraft.network.FriendlyByteBuf.DEFAULT_NBT_QUOTA)); // Paper - adventure + public static final StreamCodec> OPTIONAL_STREAM_CODEC = STREAM_CODEC.apply(ByteBufCodecs::optional); +- public static final StreamCodec TRUSTED_STREAM_CODEC = ByteBufCodecs.fromCodecWithRegistriesTrusted(CODEC); ++ // Paper start - adventure; use locale from bytebuf for translation ++ public static final ThreadLocal DONT_RENDER_TRANSLATABLES = ThreadLocal.withInitial(() -> false); ++ public static final StreamCodec TRUSTED_STREAM_CODEC = createTranslationAware(net.minecraft.nbt.NbtAccounter::unlimitedHeap); ++ private static StreamCodec createTranslationAware(final Supplier sizeTracker) { ++ return new StreamCodec<>() { ++ final StreamCodec streamCodec = ByteBufCodecs.tagCodec(sizeTracker); ++ @Override ++ public Component decode(RegistryFriendlyByteBuf registryFriendlyByteBuf) { ++ net.minecraft.nbt.Tag tag = this.streamCodec.decode(registryFriendlyByteBuf); ++ RegistryOps registryOps = registryFriendlyByteBuf.registryAccess().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE); ++ return CODEC.parse(registryOps, tag).getOrThrow(error -> new io.netty.handler.codec.DecoderException("Failed to decode: " + error + " " + tag)); ++ } ++ ++ @Override ++ public void encode(RegistryFriendlyByteBuf registryFriendlyByteBuf, Component object) { ++ RegistryOps registryOps = registryFriendlyByteBuf.registryAccess().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE); ++ net.minecraft.nbt.Tag tag = (DONT_RENDER_TRANSLATABLES.get() ? CODEC : ComponentSerialization.localizedCodec(registryFriendlyByteBuf.adventure$locale)) ++ .encodeStart(registryOps, object).getOrThrow(error -> new io.netty.handler.codec.EncoderException("Failed to encode: " + error + " " + object)); ++ this.streamCodec.encode(registryFriendlyByteBuf, tag); ++ } ++ }; ++ } ++ // Paper end - adventure; use locale from bytebuf for translation + public static final StreamCodec> TRUSTED_OPTIONAL_STREAM_CODEC = TRUSTED_STREAM_CODEC.apply( + ByteBufCodecs::optional + ); +@@ -100,7 +122,27 @@ + return ExtraCodecs.orCompressed(mapCodec3, mapCodec2); + } + ++ // Paper start - adventure; create separate codec for each locale ++ private static final java.util.Map> LOCALIZED_CODECS = new java.util.concurrent.ConcurrentHashMap<>(); ++ ++ public static Codec localizedCodec(final java.util.@org.checkerframework.checker.nullness.qual.Nullable Locale locale) { ++ if (locale == null) { ++ return CODEC; ++ } ++ return LOCALIZED_CODECS.computeIfAbsent(locale, ++ loc -> Codec.recursive("Component", selfCodec -> createCodec(selfCodec, loc))); ++ } ++ ++ ++ // Paper end - adventure; create separate codec for each locale ++ + private static Codec createCodec(Codec selfCodec) { ++ // Paper start - adventure; create separate codec for each locale ++ return createCodec(selfCodec, null); ++ } ++ ++ private static Codec createCodec(Codec selfCodec, @javax.annotation.Nullable java.util.Locale locale) { ++ // Paper end - adventure; create separate codec for each locale + ComponentContents.Type[] types = new ComponentContents.Type[]{ + PlainTextContents.TYPE, TranslatableContents.TYPE, KeybindContents.TYPE, ScoreContents.TYPE, SelectorContents.TYPE, NbtContents.TYPE + }; +@@ -113,6 +155,34 @@ + ) + .apply(instance, MutableComponent::new) + ); ++ // Paper start - adventure; create separate codec for each locale ++ final Codec origCodec = codec; ++ codec = new Codec<>() { ++ @Override ++ public DataResult> decode(final DynamicOps ops, final T input) { ++ return origCodec.decode(ops, input); ++ } ++ ++ @Override ++ public DataResult encode(final Component input, final DynamicOps ops, final T prefix) { ++ final net.kyori.adventure.text.Component adventureComponent; ++ if (input instanceof io.papermc.paper.adventure.AdventureComponent adv) { ++ adventureComponent = adv.adventure$component(); ++ } else if (locale != null && input.getContents() instanceof TranslatableContents && io.papermc.paper.adventure.PaperAdventure.hasAnyTranslations()) { ++ adventureComponent = io.papermc.paper.adventure.PaperAdventure.asAdventure(input); ++ } else { ++ return origCodec.encode(input, ops, prefix); ++ } ++ return io.papermc.paper.adventure.PaperAdventure.localizedCodec(locale) ++ .encode(adventureComponent, ops, prefix); ++ } ++ ++ @Override ++ public String toString() { ++ return origCodec.toString() + "[AdventureComponentAware]"; ++ } ++ }; ++ // Paper end - adventure; create separate codec for each locale + return Codec.either(Codec.either(Codec.STRING, ExtraCodecs.nonEmptyList(selfCodec.listOf())), codec) + .xmap(either -> either.map(either2 -> either2.map(Component::literal, ComponentSerialization::createFromList), text -> (Component)text), text -> { + String string = text.tryCollapseToString(); diff --git a/paper-server/patches/sources/net/minecraft/network/chat/ComponentUtils.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/ComponentUtils.java.patch new file mode 100644 index 0000000000..f2b2243462 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/network/chat/ComponentUtils.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/network/chat/ComponentUtils.java ++++ b/net/minecraft/network/chat/ComponentUtils.java +@@ -41,6 +41,11 @@ + if (depth > 100) { + return text.copy(); + } else { ++ // Paper start - adventure; pass actual vanilla component ++ if (text instanceof io.papermc.paper.adventure.AdventureComponent adventureComponent) { ++ text = adventureComponent.deepConverted(); ++ } ++ // Paper end - adventure; pass actual vanilla component + MutableComponent mutableComponent = text.getContents().resolve(source, sender, depth + 1); + + for (Component component : text.getSiblings()) { diff --git a/paper-server/patches/sources/net/minecraft/network/chat/MessageSignature.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/MessageSignature.java.patch new file mode 100644 index 0000000000..2b6f690732 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/network/chat/MessageSignature.java.patch @@ -0,0 +1,10 @@ +--- a/net/minecraft/network/chat/MessageSignature.java ++++ b/net/minecraft/network/chat/MessageSignature.java +@@ -13,6 +13,7 @@ + import net.minecraft.util.SignatureValidator; + + public record MessageSignature(byte[] bytes) { ++ public net.kyori.adventure.chat.SignedMessage.Signature adventure() { return () -> this.bytes; } // Paper - adventure; support signed messages + public static final Codec CODEC = ExtraCodecs.BASE64_STRING.xmap(MessageSignature::new, MessageSignature::bytes); + public static final int BYTES = 256; + diff --git a/paper-server/patches/sources/net/minecraft/network/chat/MutableComponent.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/MutableComponent.java.patch new file mode 100644 index 0000000000..c4694faca6 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/network/chat/MutableComponent.java.patch @@ -0,0 +1,14 @@ +--- a/net/minecraft/network/chat/MutableComponent.java ++++ b/net/minecraft/network/chat/MutableComponent.java +@@ -94,6 +94,11 @@ + + @Override + public boolean equals(Object object) { ++ // Paper start - make AdventureComponent equivalent ++ if (object instanceof io.papermc.paper.adventure.AdventureComponent adventureComponent) { ++ object = adventureComponent.deepConverted(); ++ } ++ // Paper end - make AdventureComponent equivalent + return this == object + || object instanceof MutableComponent mutableComponent + && this.contents.equals(mutableComponent.contents) diff --git a/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch new file mode 100644 index 0000000000..3192e18db3 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/network/chat/OutgoingChatMessage.java.patch @@ -0,0 +1,44 @@ +--- a/net/minecraft/network/chat/OutgoingChatMessage.java ++++ b/net/minecraft/network/chat/OutgoingChatMessage.java +@@ -7,6 +7,12 @@ + + void sendToPlayer(ServerPlayer sender, boolean filterMaskEnabled, ChatType.Bound params); + ++ // Paper start ++ default void sendToPlayer(ServerPlayer sender, boolean filterMaskEnabled, ChatType.Bound params, @javax.annotation.Nullable Component unsigned) { ++ this.sendToPlayer(sender, filterMaskEnabled, params); ++ } ++ // Paper end ++ + static OutgoingChatMessage create(PlayerChatMessage message) { + return (OutgoingChatMessage)(message.isSystem() + ? new OutgoingChatMessage.Disguised(message.decoratedContent()) +@@ -16,8 +22,13 @@ + public static record Disguised(@Override Component content) implements OutgoingChatMessage { + @Override + public void sendToPlayer(ServerPlayer sender, boolean filterMaskEnabled, ChatType.Bound params) { +- sender.connection.sendDisguisedChatMessage(this.content, params); ++ // Paper start ++ this.sendToPlayer(sender, filterMaskEnabled, params, null); + } ++ public void sendToPlayer(ServerPlayer sender, boolean filterMaskEnabled, ChatType.Bound params, @javax.annotation.Nullable Component unsigned) { ++ sender.connection.sendDisguisedChatMessage(unsigned != null ? unsigned : this.content, params); ++ // Paper end ++ } + } + + public static record Player(PlayerChatMessage message) implements OutgoingChatMessage { +@@ -28,7 +39,13 @@ + + @Override + public void sendToPlayer(ServerPlayer sender, boolean filterMaskEnabled, ChatType.Bound params) { ++ // Paper start ++ this.sendToPlayer(sender, filterMaskEnabled, params, null); ++ } ++ public void sendToPlayer(ServerPlayer sender, boolean filterMaskEnabled, ChatType.Bound params, @javax.annotation.Nullable Component unsigned) { ++ // Paper end + PlayerChatMessage playerChatMessage = this.message.filter(filterMaskEnabled); ++ playerChatMessage = unsigned != null ? playerChatMessage.withUnsignedContent(unsigned) : playerChatMessage; // Paper + if (!playerChatMessage.isFullyFiltered()) { + sender.connection.sendPlayerChatMessage(playerChatMessage, params); + } diff --git a/paper-server/patches/sources/net/minecraft/network/chat/PlayerChatMessage.java.patch b/paper-server/patches/sources/net/minecraft/network/chat/PlayerChatMessage.java.patch new file mode 100644 index 0000000000..8722bc8269 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/network/chat/PlayerChatMessage.java.patch @@ -0,0 +1,61 @@ +--- a/net/minecraft/network/chat/PlayerChatMessage.java ++++ b/net/minecraft/network/chat/PlayerChatMessage.java +@@ -17,6 +17,42 @@ + public record PlayerChatMessage( + SignedMessageLink link, @Nullable MessageSignature signature, SignedMessageBody signedBody, @Nullable Component unsignedContent, FilterMask filterMask + ) { ++ // Paper start - adventure; support signed messages ++ public final class AdventureView implements net.kyori.adventure.chat.SignedMessage { ++ private AdventureView() { ++ } ++ @Override ++ public @org.jetbrains.annotations.NotNull Instant timestamp() { ++ return PlayerChatMessage.this.timeStamp(); ++ } ++ @Override ++ public long salt() { ++ return PlayerChatMessage.this.salt(); ++ } ++ @Override ++ public @org.jetbrains.annotations.Nullable Signature signature() { ++ return PlayerChatMessage.this.signature == null ? null : PlayerChatMessage.this.signature.adventure(); ++ } ++ @Override ++ public net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component unsignedContent() { ++ return PlayerChatMessage.this.unsignedContent() == null ? null : io.papermc.paper.adventure.PaperAdventure.asAdventure(PlayerChatMessage.this.unsignedContent()); ++ } ++ @Override ++ public @org.jetbrains.annotations.NotNull String message() { ++ return PlayerChatMessage.this.signedContent(); ++ } ++ @Override ++ public @org.jetbrains.annotations.NotNull net.kyori.adventure.identity.Identity identity() { ++ return net.kyori.adventure.identity.Identity.identity(PlayerChatMessage.this.sender()); ++ } ++ public PlayerChatMessage playerChatMessage() { ++ return PlayerChatMessage.this; ++ } ++ } ++ public AdventureView adventureView() { ++ return new AdventureView(); ++ } ++ // Paper end - adventure; support signed messages + public static final MapCodec MAP_CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + SignedMessageLink.CODEC.fieldOf("link").forGetter(PlayerChatMessage::link), +@@ -47,7 +83,14 @@ + } + + public PlayerChatMessage withUnsignedContent(Component unsignedContent) { +- Component component = !unsignedContent.equals(Component.literal(this.signedContent())) ? unsignedContent : null; ++ // Paper start - adventure ++ final Component component; ++ if (unsignedContent instanceof io.papermc.paper.adventure.AdventureComponent advComponent) { ++ component = this.signedContent().equals(io.papermc.paper.adventure.AdventureCodecs.tryCollapseToString(advComponent.adventure$component())) ? null : unsignedContent; ++ } else { ++ component = !unsignedContent.equals(Component.literal(this.signedContent())) ? unsignedContent : null; ++ } ++ // Paper end - adventure + return new PlayerChatMessage(this.link, this.signature, this.signedBody, component, this.filterMask); + } + diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java.patch index 048868c319..64187dddbd 100644 --- a/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java.patch +++ b/paper-server/patches/sources/net/minecraft/network/protocol/game/ClientboundSystemChatPacket.java.patch @@ -5,7 +5,7 @@ package net.minecraft.network.protocol.game; import net.minecraft.network.RegistryFriendlyByteBuf; -@@ -12,6 +13,12 @@ +@@ -12,6 +13,17 @@ public static final StreamCodec STREAM_CODEC = StreamCodec.composite(ComponentSerialization.TRUSTED_STREAM_CODEC, ClientboundSystemChatPacket::content, ByteBufCodecs.BOOL, ClientboundSystemChatPacket::overlay, ClientboundSystemChatPacket::new); @@ -14,6 +14,11 @@ + this(org.bukkit.craftbukkit.util.CraftChatMessage.fromJSON(net.md_5.bungee.chat.ComponentSerializer.toString(content)), overlay); + } + // Spigot end ++ // Paper start ++ public ClientboundSystemChatPacket(net.kyori.adventure.text.Component content, boolean overlay) { ++ this(io.papermc.paper.adventure.PaperAdventure.asVanilla(content), overlay); ++ } ++ // Paper end + @Override public PacketType type() { diff --git a/paper-server/patches/sources/net/minecraft/network/protocol/login/ClientboundLoginDisconnectPacket.java.patch b/paper-server/patches/sources/net/minecraft/network/protocol/login/ClientboundLoginDisconnectPacket.java.patch new file mode 100644 index 0000000000..7ad1ef4a1c --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/network/protocol/login/ClientboundLoginDisconnectPacket.java.patch @@ -0,0 +1,21 @@ +--- a/net/minecraft/network/protocol/login/ClientboundLoginDisconnectPacket.java ++++ b/net/minecraft/network/protocol/login/ClientboundLoginDisconnectPacket.java +@@ -18,11 +18,16 @@ + } + + private ClientboundLoginDisconnectPacket(FriendlyByteBuf buf) { +- this.reason = Component.Serializer.fromJsonLenient(buf.readUtf(262144), RegistryAccess.EMPTY); ++ this.reason = Component.Serializer.fromJsonLenient(buf.readUtf(FriendlyByteBuf.MAX_COMPONENT_STRING_LENGTH), RegistryAccess.EMPTY); // Paper - diff on change + } + + private void write(FriendlyByteBuf buf) { +- buf.writeUtf(Component.Serializer.toJson(this.reason, RegistryAccess.EMPTY)); ++ // Paper start - Adventure ++ // buf.writeUtf(Component.Serializer.toJson(this.reason, RegistryAccess.EMPTY)); ++ // In the login phase, buf.adventure$locale field is most likely null, but plugins may use internals to set it via the channel attribute ++ java.util.Locale bufLocale = buf.adventure$locale; ++ buf.writeJsonWithCodec(net.minecraft.network.chat.ComponentSerialization.localizedCodec(bufLocale == null ? java.util.Locale.US : bufLocale), this.reason, FriendlyByteBuf.MAX_COMPONENT_STRING_LENGTH); ++ // Paper end - Adventure + } + + @Override diff --git a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch index 04b472a44d..c3a4e36394 100644 --- a/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -26,7 +26,7 @@ import net.minecraft.util.debugchart.RemoteDebugSampleType; import net.minecraft.util.debugchart.SampleLogger; import net.minecraft.util.debugchart.TpsDebugDimensions; -@@ -156,37 +146,72 @@ +@@ -156,37 +146,73 @@ import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.FuelValues; @@ -99,6 +99,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource { public static final Logger LOGGER = LogUtils.getLogger(); ++ public static final net.kyori.adventure.text.logger.slf4j.ComponentLogger COMPONENT_LOGGER = net.kyori.adventure.text.logger.slf4j.ComponentLogger.logger(LOGGER.getName()); // Paper public static final String VANILLA_BRAND = "vanilla"; private static final float AVERAGE_TICK_TIME_SMOOTHING = 0.8F; private static final int TICK_STATS_SPAN = 100; @@ -107,10 +108,21 @@ private static final int OVERLOADED_TICKS_THRESHOLD = 20; private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeUtil.NANOSECONDS_PER_SECOND; private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100; -@@ -277,6 +302,26 @@ +@@ -232,8 +258,7 @@ + private boolean preventProxyConnections; + private boolean pvp; + private boolean allowFlight; +- @Nullable +- private String motd; ++ private net.kyori.adventure.text.Component motd; // Paper - Adventure + private int playerIdleTimeout; + private final long[] tickTimesNanos; + private long aggregatedTickTimesNanos; +@@ -276,6 +301,26 @@ + private static final AtomicReference fatalException = new AtomicReference(); private final SuppressedExceptionCollector suppressedExceptions; private final DiscontinuousFrame tickFrame; - ++ + // CraftBukkit start + public final WorldLoader.DataLoadContext worldLoader; + public org.bukkit.craftbukkit.CraftServer server; @@ -130,10 +142,9 @@ + public final double[] recentTps = new double[ 3 ]; + // Spigot end + public final io.papermc.paper.configuration.PaperConfigurations paperConfigurations; // Paper - add paper configuration files -+ + public static S spin(Function serverFactory) { AtomicReference atomicreference = new AtomicReference(); - Thread thread = new Thread(() -> { @@ -290,14 +335,14 @@ thread.setPriority(8); } @@ -723,7 +734,7 @@ this.nextTickTimeNanos += k * i; this.lastOverloadWarningNanos = this.nextTickTimeNanos; } -+ } + } + // Spigot start + if ( tickCount++ % MinecraftServer.SAMPLE_INTERVAL == 0 ) + { @@ -733,7 +744,7 @@ + this.recentTps[1] = MinecraftServer.calcTps( this.recentTps[1], 0.9835, currentTps ); // 1/exp(5sec/5min) + this.recentTps[2] = MinecraftServer.calcTps( this.recentTps[2], 0.9945, currentTps ); // 1/exp(5sec/15min) + tickSection = curTime; - } ++ } + // Spigot end boolean flag = i == 0L; @@ -850,13 +861,23 @@ } private void logTickMethodTime(long tickStartTime) { -@@ -1154,11 +1501,34 @@ +@@ -1123,7 +1470,7 @@ + private ServerStatus buildServerStatus() { + ServerStatus.Players serverping_serverpingplayersample = this.buildPlayerStatus(); + +- return new ServerStatus(Component.nullToEmpty(this.motd), Optional.of(serverping_serverpingplayersample), Optional.of(ServerStatus.Version.current()), Optional.ofNullable(this.statusIcon), this.enforceSecureProfile()); ++ return new ServerStatus(io.papermc.paper.adventure.PaperAdventure.asVanilla(this.motd), Optional.of(serverping_serverpingplayersample), Optional.of(ServerStatus.Version.current()), Optional.ofNullable(this.statusIcon), this.enforceSecureProfile()); // Paper - Adventure + } + + private ServerStatus.Players buildPlayerStatus() { +@@ -1154,11 +1501,35 @@ this.getPlayerList().getPlayers().forEach((entityplayer) -> { entityplayer.connection.suspendFlushing(); }); + SpigotTimings.schedulerTimer.startTiming(); // Spigot + this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit + SpigotTimings.schedulerTimer.stopTiming(); // Spigot ++ io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper gameprofilerfiller.push("commandFunctions"); + SpigotTimings.commandFunctionsTimer.startTiming(); // Spigot this.getFunctions().tick(); @@ -885,7 +906,7 @@ while (iterator.hasNext()) { ServerLevel worldserver = (ServerLevel) iterator.next(); -@@ -1167,16 +1537,20 @@ +@@ -1167,16 +1538,20 @@ return s + " " + String.valueOf(worldserver.dimension().location()); }); @@ -906,7 +927,7 @@ } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world"); -@@ -1189,18 +1563,24 @@ +@@ -1189,18 +1564,24 @@ } gameprofilerfiller.popPush("connection"); @@ -931,12 +952,10 @@ gameprofilerfiller.popPush("send chunks"); iterator = this.playerList.getPlayers().iterator(); -@@ -1265,7 +1645,23 @@ - @Nullable - public ServerLevel getLevel(ResourceKey key) { +@@ -1267,6 +1648,22 @@ return (ServerLevel) this.levels.get(key); -+ } -+ + } + + // CraftBukkit start + public void addLevel(ServerLevel level) { + Map, ServerLevel> oldLevels = this.levels; @@ -950,12 +969,13 @@ + Map, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels); + newLevels.remove(level.dimension()); + this.levels = Collections.unmodifiableMap(newLevels); - } ++ } + // CraftBukkit end - ++ public Set> levelKeys() { return this.levels.keySet(); -@@ -1296,7 +1692,7 @@ + } +@@ -1296,7 +1693,7 @@ @DontObfuscate public String getServerModName() { @@ -964,7 +984,29 @@ } public SystemReport fillSystemReport(SystemReport details) { -@@ -1507,7 +1903,7 @@ +@@ -1481,10 +1878,20 @@ + + @Override + public String getMotd() { +- return this.motd; ++ return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().serialize(this.motd); // Paper - Adventure + } + + public void setMotd(String motd) { ++ // Paper start - Adventure ++ this.motd = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserializeOr(motd, net.kyori.adventure.text.Component.empty()); ++ } ++ ++ public net.kyori.adventure.text.Component motd() { ++ return this.motd; ++ } ++ ++ public void motd(net.kyori.adventure.text.Component motd) { ++ // Paper end - Adventure + this.motd = motd; + } + +@@ -1507,7 +1914,7 @@ } public ServerConnectionListener getConnection() { @@ -973,7 +1015,7 @@ } public boolean isReady() { -@@ -1634,11 +2030,11 @@ +@@ -1634,11 +2041,11 @@ public CompletableFuture reloadResources(Collection dataPacks) { CompletableFuture completablefuture = CompletableFuture.supplyAsync(() -> { @@ -987,7 +1029,7 @@ }, this).thenCompose((immutablelist) -> { MultiPackResourceManager resourcemanager = new MultiPackResourceManager(PackType.SERVER_DATA, immutablelist); List> list = TagLoader.loadTagsForExistingRegistries(resourcemanager, this.registries.compositeAccess()); -@@ -1654,6 +2050,7 @@ +@@ -1654,6 +2061,7 @@ }).thenAcceptAsync((minecraftserver_reloadableresources) -> { this.resources.close(); this.resources = minecraftserver_reloadableresources; @@ -995,7 +1037,7 @@ this.packRepository.setSelected(dataPacks); WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(MinecraftServer.getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()); -@@ -1952,7 +2349,7 @@ +@@ -1952,7 +2360,7 @@ final List list = Lists.newArrayList(); final GameRules gamerules = this.getGameRules(); @@ -1004,7 +1046,7 @@ @Override public > void visit(GameRules.Key key, GameRules.Type type) { list.add(String.format(Locale.ROOT, "%s=%s\n", key.getId(), gamerules.getRule(key))); -@@ -2058,7 +2455,7 @@ +@@ -2058,7 +2466,7 @@ try { label51: { @@ -1013,40 +1055,58 @@ try { arraylist = Lists.newArrayList(NativeModuleLister.listModules()); -@@ -2105,8 +2502,24 @@ +@@ -2105,9 +2513,25 @@ if (bufferedwriter != null) { bufferedwriter.close(); } + + } -+ + + // CraftBukkit start + public boolean isDebugging() { + return false; -+ } -+ + } + + @Deprecated + public static MinecraftServer getServer() { + return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null; + } - ++ + @Deprecated + public static RegistryAccess getDefaultRegistryAccess() { + return CraftRegistry.getMinecraftRegistry(); - } -+ // CraftBukkit end - - private ProfilerFiller createProfiler() { - if (this.willStartRecordingMetrics) { -@@ -2235,6 +2648,11 @@ - - } - -+ // CraftBukkit start -+ public final java.util.concurrent.ExecutorService chatExecutor = java.util.concurrent.Executors.newCachedThreadPool( -+ new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Async Chat Thread - #%d").build()); ++ } + // CraftBukkit end + - public ChatDecorator getChatDecorator() { - return ChatDecorator.PLAIN; + private ProfilerFiller createProfiler() { + if (this.willStartRecordingMetrics) { + this.metricsRecorder = ActiveMetricsRecorder.createStarted(new ServerMetricsSamplersProvider(Util.timeSource, this.isDedicatedServer()), Util.timeSource, Util.ioPool(), new MetricsPersister("server"), this.onMetricsRecordingStopped, (path) -> { +@@ -2225,18 +2649,24 @@ } + + public void logChatMessage(Component message, ChatType.Bound params, @Nullable String prefix) { +- String s1 = params.decorate(message).getString(); ++ // Paper start ++ net.kyori.adventure.text.Component s1 = io.papermc.paper.adventure.PaperAdventure.asAdventure(params.decorate(message)); + + if (prefix != null) { +- MinecraftServer.LOGGER.info("[{}] {}", prefix, s1); ++ MinecraftServer.COMPONENT_LOGGER.info("[{}] {}", prefix, s1); + } else { +- MinecraftServer.LOGGER.info("{}", s1); ++ MinecraftServer.COMPONENT_LOGGER.info("{}", s1); ++ // Paper end + } + + } + ++ public final java.util.concurrent.ExecutorService chatExecutor = java.util.concurrent.Executors.newCachedThreadPool( ++ new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Async Chat Thread - #%d").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build()); // Paper ++ ++ public final ChatDecorator improvedChatDecorator = new io.papermc.paper.adventure.ImprovedChatDecorator(this); // Paper - adventure + public ChatDecorator getChatDecorator() { +- return ChatDecorator.PLAIN; ++ return this.improvedChatDecorator; // Paper - support async chat decoration events + } + + public boolean logIPs() { diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch index ca14722da1..670c05fd2b 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayer.java.patch @@ -53,7 +53,7 @@ import net.minecraft.world.level.gameevent.GameEvent; import net.minecraft.world.level.portal.TeleportTransition; import net.minecraft.world.level.saveddata.maps.MapId; -@@ -179,11 +176,47 @@ +@@ -179,11 +176,48 @@ import net.minecraft.world.scores.PlayerTeam; import net.minecraft.world.scores.ScoreAccess; import net.minecraft.world.scores.ScoreHolder; @@ -71,6 +71,7 @@ import net.minecraft.world.scores.Team; import net.minecraft.world.scores.criteria.ObjectiveCriteria; -import org.slf4j.Logger; ++import io.papermc.paper.adventure.PaperAdventure; // Paper +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.WeatherType; @@ -103,23 +104,24 @@ private static final Logger LOGGER = LogUtils.getLogger(); private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32; -@@ -225,7 +258,7 @@ +@@ -225,7 +259,8 @@ private int levitationStartTime; private boolean disconnected; private int requestedViewDistance; - public String language; + public String language = "en_us"; // CraftBukkit - default ++ public java.util.Locale adventure$locale = java.util.Locale.US; // Paper @Nullable private Vec3 startingToFallPosition; @Nullable -@@ -258,6 +291,23 @@ - private final CommandSource commandSource; +@@ -259,6 +294,24 @@ private int containerCounter; public boolean wonGame; -+ + + // CraftBukkit start + public CraftPlayer.TransferCookieConnection transferCookieConnection; + public String displayName; ++ public net.kyori.adventure.text.Component adventure$displayName; // Paper + public Component listName; + public int listOrder = 0; + public org.bukkit.Location compassTarget; @@ -133,10 +135,11 @@ + public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent + // CraftBukkit end + public boolean isRealPlayer; // Paper - ++ public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); -@@ -340,6 +390,13 @@ + this.chatVisibility = ChatVisiblity.FULL; +@@ -340,6 +393,13 @@ public void sendSystemMessage(Component message) { ServerPlayer.this.sendSystemMessage(message); } @@ -150,13 +153,14 @@ }; this.textFilter = server.createTextFilterForPlayer(this); this.gameMode = server.createGameModeForPlayer(this); -@@ -352,14 +409,67 @@ +@@ -352,14 +412,68 @@ this.moveTo(this.adjustSpawnLocation(world, world.getSharedSpawnPos()).getBottomCenter(), 0.0F, 0.0F); this.updateOptions(clientOptions); this.object = null; + + // CraftBukkit start + this.displayName = this.getScoreboardName(); ++ this.adventure$displayName = net.kyori.adventure.text.Component.text(this.getScoreboardName()); // Paper + this.bukkitPickUpLoot = true; + this.maxHealthCache = this.getMaxHealth(); + } @@ -219,7 +223,7 @@ int i = Math.max(0, this.server.getSpawnRadius(world)); int j = Mth.floor(world.getWorldBorder().getDistanceToBorder((double) basePos.getX(), (double) basePos.getZ())); -@@ -395,14 +505,20 @@ +@@ -395,14 +509,20 @@ Objects.requireNonNull(basePos); crashreportsystemdetails.setDetail("Origin", basePos::toString); @@ -242,7 +246,7 @@ }); throw new ReportedException(crashreport); } -@@ -440,7 +556,7 @@ +@@ -440,7 +560,7 @@ dataresult = WardenSpawnTracker.CODEC.parse(new Dynamic(NbtOps.INSTANCE, nbt.get("warden_spawn_tracker"))); logger = ServerPlayer.LOGGER; Objects.requireNonNull(logger); @@ -251,7 +255,7 @@ this.wardenSpawnTracker = wardenspawntracker; }); } -@@ -457,17 +573,26 @@ +@@ -457,17 +577,26 @@ return this.server.getRecipeManager().byKey(resourcekey).isPresent(); }); } @@ -279,7 +283,7 @@ Logger logger1 = ServerPlayer.LOGGER; Objects.requireNonNull(logger1); -@@ -482,7 +607,7 @@ +@@ -482,7 +611,7 @@ dataresult = BlockPos.CODEC.parse(NbtOps.INSTANCE, nbtbase); logger = ServerPlayer.LOGGER; Objects.requireNonNull(logger); @@ -288,7 +292,7 @@ this.raidOmenPosition = blockposition; }); } -@@ -492,7 +617,7 @@ +@@ -492,7 +621,7 @@ @Override public void addAdditionalSaveData(CompoundTag nbt) { super.addAdditionalSaveData(nbt); @@ -297,7 +301,7 @@ Logger logger = ServerPlayer.LOGGER; Objects.requireNonNull(logger); -@@ -526,6 +651,7 @@ +@@ -526,6 +655,7 @@ nbt.put("SpawnDimension", nbtbase); }); } @@ -305,7 +309,7 @@ nbt.putBoolean("spawn_extra_particles_on_fall", this.spawnExtraParticlesOnFall); if (this.raidOmenPosition != null) { -@@ -544,7 +670,20 @@ +@@ -544,7 +674,20 @@ Entity entity = this.getRootVehicle(); Entity entity1 = this.getVehicle(); @@ -327,7 +331,7 @@ CompoundTag nbttagcompound1 = new CompoundTag(); CompoundTag nbttagcompound2 = new CompoundTag(); -@@ -598,12 +737,12 @@ +@@ -598,12 +741,12 @@ if (!this.isPassenger()) { ServerPlayer.LOGGER.warn("Couldn't reattach entity to player"); @@ -342,7 +346,7 @@ } } } -@@ -625,7 +764,7 @@ +@@ -625,7 +768,7 @@ CompoundTag nbttagcompound1 = new CompoundTag(); entityenderpearl.save(nbttagcompound1); @@ -351,7 +355,7 @@ Logger logger = ServerPlayer.LOGGER; Objects.requireNonNull(logger); -@@ -651,7 +790,7 @@ +@@ -651,7 +794,7 @@ nbttaglist.forEach((nbtbase1) -> { if (nbtbase1 instanceof CompoundTag nbttagcompound) { if (nbttagcompound.contains("ender_pearl_dimension")) { @@ -360,7 +364,7 @@ Logger logger = ServerPlayer.LOGGER; Objects.requireNonNull(logger); -@@ -684,7 +823,30 @@ +@@ -684,7 +827,30 @@ } } @@ -391,7 +395,7 @@ public void setExperiencePoints(int points) { float f = (float) this.getXpNeededForNextLevel(); -@@ -744,6 +906,11 @@ +@@ -744,6 +910,11 @@ @Override public void tick() { @@ -403,7 +407,7 @@ this.tickClientLoadTimeout(); this.gameMode.tick(); this.wardenSpawnTracker.tick(); -@@ -820,7 +987,7 @@ +@@ -820,7 +991,7 @@ } if (this.getHealth() != this.lastSentHealth || this.lastSentFood != this.foodData.getFoodLevel() || this.foodData.getSaturationLevel() == 0.0F != this.lastFoodSaturationZero) { @@ -412,20 +416,21 @@ this.lastSentHealth = this.getHealth(); this.lastSentFood = this.foodData.getFoodLevel(); this.lastFoodSaturationZero = this.foodData.getSaturationLevel() == 0.0F; -@@ -851,6 +1018,12 @@ +@@ -849,7 +1020,13 @@ + if (this.totalExperience != this.lastRecordedExperience) { + this.lastRecordedExperience = this.totalExperience; this.updateScoreForCriteria(ObjectiveCriteria.EXPERIENCE, Mth.ceil((float) this.lastRecordedExperience)); - } - ++ } ++ + // CraftBukkit start - Force max health updates + if (this.maxHealthCache != this.getMaxHealth()) { + this.getBukkitEntity().updateScaledHealth(); -+ } + } + // CraftBukkit end -+ + if (this.experienceLevel != this.lastRecordedLevel) { this.lastRecordedLevel = this.experienceLevel; - this.updateScoreForCriteria(ObjectiveCriteria.LEVEL, Mth.ceil((float) this.lastRecordedLevel)); -@@ -865,6 +1038,20 @@ +@@ -865,6 +1042,20 @@ CriteriaTriggers.LOCATION.trigger(this); } @@ -446,7 +451,7 @@ } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Ticking player"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Player being ticked"); -@@ -893,7 +1080,7 @@ +@@ -893,7 +1084,7 @@ if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.serverLevel().getGameRules().getBoolean(GameRules.RULE_NATURAL_REGENERATION)) { if (this.tickCount % 20 == 0) { if (this.getHealth() < this.getMaxHealth()) { @@ -455,7 +460,7 @@ } float f = this.foodData.getSaturationLevel(); -@@ -946,7 +1133,8 @@ +@@ -946,7 +1137,8 @@ } private void updateScoreForCriteria(ObjectiveCriteria criterion, int score) { @@ -465,7 +470,7 @@ scoreaccess.set(score); }); } -@@ -955,9 +1143,47 @@ +@@ -955,10 +1147,43 @@ public void die(DamageSource damageSource) { this.gameEvent(GameEvent.ENTITY_DIE); boolean flag = this.serverLevel().getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES); @@ -488,7 +493,7 @@ + // SPIGOT-5071: manually add player loot tables (SPIGOT-5195 - ignores keepInventory rule) + this.dropFromLootTable(this.serverLevel(), damageSource, this.lastHurtByPlayerTime > 0); + this.dropCustomDeathLoot(this.serverLevel(), damageSource, flag); -+ + + loot.addAll(this.drops); + this.drops.clear(); // SPIGOT-5188: make sure to clear + @@ -496,26 +501,22 @@ + + String deathmessage = defaultMessage.getString(); + this.keepLevel = keepInventory; // SPIGOT-2222: pre-set keepLevel -+ org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, damageSource, loot, deathmessage, keepInventory); ++ org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, damageSource, loot, PaperAdventure.asAdventure(defaultMessage), keepInventory); // Paper - Adventure + + // SPIGOT-943 - only call if they have an inventory open + if (this.containerMenu != this.inventoryMenu) { + this.closeContainer(); + } + -+ String deathMessage = event.getDeathMessage(); ++ net.kyori.adventure.text.Component deathMessage = event.deathMessage() != null ? event.deathMessage() : net.kyori.adventure.text.Component.empty(); // Paper - Adventure ++ ++ if (deathMessage != null && deathMessage != net.kyori.adventure.text.Component.empty() && flag) { // Paper - Adventure // TODO: allow plugins to override? ++ Component ichatbasecomponent = PaperAdventure.asVanilla(deathMessage); // Paper - Adventure + -+ if (deathMessage != null && deathMessage.length() > 0 && flag) { // TODO: allow plugins to override? -+ Component ichatbasecomponent; -+ if (deathMessage.equals(deathmessage)) { -+ ichatbasecomponent = this.getCombatTracker().getDeathMessage(); -+ } else { -+ ichatbasecomponent = org.bukkit.craftbukkit.util.CraftChatMessage.fromStringOrNull(deathMessage); -+ } - this.connection.send(new ClientboundPlayerCombatKillPacket(this.getId(), ichatbasecomponent), PacketSendListener.exceptionallySend(() -> { boolean flag1 = true; -@@ -988,12 +1214,18 @@ + String s = ichatbasecomponent.getString(256); +@@ -988,12 +1213,18 @@ if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_FORGIVE_DEAD_PLAYERS)) { this.tellNeutralMobsThatIDied(); } @@ -538,7 +539,7 @@ LivingEntity entityliving = this.getKillCredit(); if (entityliving != null) { -@@ -1028,10 +1260,12 @@ +@@ -1028,10 +1259,12 @@ public void awardKillScore(Entity entityKilled, DamageSource damageSource) { if (entityKilled != this) { super.awardKillScore(entityKilled, damageSource); @@ -554,7 +555,7 @@ } else { this.awardStat(Stats.MOB_KILLS); } -@@ -1049,7 +1283,8 @@ +@@ -1049,7 +1282,8 @@ int i = scoreboardteam.getColor().getId(); if (i >= 0 && i < criterions.length) { @@ -564,7 +565,7 @@ } } -@@ -1062,8 +1297,8 @@ +@@ -1062,8 +1296,8 @@ } else { Entity entity = source.getEntity(); @@ -575,7 +576,7 @@ if (!this.canHarmPlayer(entityhuman)) { return false; -@@ -1074,8 +1309,8 @@ +@@ -1074,8 +1308,8 @@ AbstractArrow entityarrow = (AbstractArrow) entity; Entity entity1 = entityarrow.getOwner(); @@ -586,7 +587,7 @@ if (!this.canHarmPlayer(entityhuman1)) { return false; -@@ -1088,33 +1323,63 @@ +@@ -1088,33 +1322,63 @@ } @Override @@ -657,7 +658,7 @@ } public static Optional findRespawnAndUseSpawnBlock(ServerLevel world, BlockPos pos, float spawnAngle, boolean spawnForced, boolean alive) { -@@ -1129,11 +1394,11 @@ +@@ -1129,11 +1393,11 @@ } return optional.map((vec3d) -> { @@ -671,7 +672,7 @@ }); } else if (!spawnForced) { return Optional.empty(); -@@ -1142,7 +1407,7 @@ +@@ -1142,7 +1406,7 @@ BlockState iblockdata1 = world.getBlockState(pos.above()); boolean flag3 = iblockdata1.getBlock().isPossibleToRespawnInThis(iblockdata1); @@ -680,7 +681,7 @@ } } -@@ -1160,6 +1425,7 @@ +@@ -1160,6 +1424,7 @@ @Nullable @Override public ServerPlayer teleport(TeleportTransition teleportTarget) { @@ -688,7 +689,7 @@ if (this.isRemoved()) { return null; } else { -@@ -1169,39 +1435,73 @@ +@@ -1169,39 +1434,73 @@ ServerLevel worldserver = teleportTarget.newLevel(); ServerLevel worldserver1 = this.serverLevel(); @@ -770,7 +771,7 @@ this.connection.resetPosition(); worldserver.addDuringTeleport(this); gameprofilerfiller.pop(); -@@ -1215,12 +1515,30 @@ +@@ -1215,12 +1514,30 @@ this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; @@ -801,7 +802,7 @@ public void forceSetRotation(float yaw, float pitch) { this.connection.send(new ClientboundPlayerRotationPacket(yaw, pitch)); } -@@ -1228,13 +1546,21 @@ +@@ -1228,13 +1545,21 @@ public void triggerDimensionChangeTriggers(ServerLevel origin) { ResourceKey resourcekey = origin.dimension(); ResourceKey resourcekey1 = this.level().dimension(); @@ -826,7 +827,7 @@ this.enteredNetherPosition = null; } -@@ -1251,36 +1577,63 @@ +@@ -1251,36 +1576,63 @@ this.containerMenu.broadcastChanges(); } @@ -905,7 +906,7 @@ this.awardStat(Stats.SLEEP_IN_BED); CriteriaTriggers.SLEPT_IN_BED.trigger(this); }); -@@ -1293,9 +1646,8 @@ +@@ -1293,9 +1645,8 @@ return either; } } @@ -916,7 +917,7 @@ } @Override -@@ -1322,13 +1674,31 @@ +@@ -1322,13 +1673,31 @@ @Override public void stopSleepInBed(boolean skipSleepTimer, boolean updateSleepingPlayers) { @@ -949,7 +950,7 @@ } } -@@ -1387,8 +1757,9 @@ +@@ -1387,8 +1756,9 @@ this.connection.send(new ClientboundOpenSignEditorPacket(sign.getBlockPos(), front)); } @@ -960,7 +961,7 @@ } @Override -@@ -1396,13 +1767,35 @@ +@@ -1396,13 +1766,35 @@ if (factory == null) { return OptionalInt.empty(); } else { @@ -996,7 +997,7 @@ if (container == null) { if (this.isSpectator()) { this.displayClientMessage(Component.translatable("container.spectatorCantOpen").withStyle(ChatFormatting.RED), true); -@@ -1410,9 +1803,11 @@ +@@ -1410,9 +1802,11 @@ return OptionalInt.empty(); } else { @@ -1010,7 +1011,7 @@ return OptionalInt.of(this.containerCounter); } } -@@ -1425,15 +1820,26 @@ +@@ -1425,15 +1819,26 @@ @Override public void openHorseInventory(AbstractHorse horse, Container inventory) { @@ -1039,7 +1040,7 @@ this.initMenu(this.containerMenu); } -@@ -1456,6 +1862,7 @@ +@@ -1456,6 +1861,7 @@ @Override public void closeContainer() { @@ -1047,7 +1048,7 @@ this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId)); this.doCloseContainer(); } -@@ -1485,19 +1892,19 @@ +@@ -1485,19 +1891,19 @@ i = Math.round((float) Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) * 100.0F); if (i > 0) { this.awardStat(Stats.SWIM_ONE_CM, i); @@ -1070,7 +1071,7 @@ } } else if (this.onClimbable()) { if (deltaY > 0.0D) { -@@ -1508,13 +1915,13 @@ +@@ -1508,13 +1914,13 @@ if (i > 0) { if (this.isSprinting()) { this.awardStat(Stats.SPRINT_ONE_CM, i); @@ -1087,7 +1088,7 @@ } } } else if (this.isFallFlying()) { -@@ -1557,7 +1964,7 @@ +@@ -1557,7 +1963,7 @@ @Override public void awardStat(Stat stat, int amount) { this.stats.increment(this, stat, amount); @@ -1096,7 +1097,7 @@ scoreaccess.add(amount); }); } -@@ -1565,7 +1972,7 @@ +@@ -1565,7 +1971,7 @@ @Override public void resetStat(Stat stat) { this.stats.setValue(this, stat, 0); @@ -1105,7 +1106,7 @@ } @Override -@@ -1597,9 +2004,9 @@ +@@ -1597,9 +2003,9 @@ super.jumpFromGround(); this.awardStat(Stats.JUMP); if (this.isSprinting()) { @@ -1117,7 +1118,7 @@ } } -@@ -1625,6 +2032,7 @@ +@@ -1625,6 +2031,7 @@ public void resetSentInfo() { this.lastSentHealth = -1.0E8F; @@ -1125,7 +1126,7 @@ } @Override -@@ -1661,7 +2069,7 @@ +@@ -1661,7 +2068,7 @@ this.onUpdateAbilities(); if (alive) { this.getAttributes().assignBaseValues(oldPlayer.getAttributes()); @@ -1134,7 +1135,7 @@ this.setHealth(oldPlayer.getHealth()); this.foodData = oldPlayer.foodData; Iterator iterator = oldPlayer.getActiveEffects().iterator(); -@@ -1669,7 +2077,7 @@ +@@ -1669,7 +2076,7 @@ while (iterator.hasNext()) { MobEffectInstance mobeffect = (MobEffectInstance) iterator.next(); @@ -1143,7 +1144,7 @@ } this.getInventory().replaceWith(oldPlayer.getInventory()); -@@ -1680,7 +2088,7 @@ +@@ -1680,7 +2087,7 @@ this.portalProcess = oldPlayer.portalProcess; } else { this.getAttributes().assignBaseValues(oldPlayer.getAttributes()); @@ -1152,7 +1153,7 @@ if (this.serverLevel().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || oldPlayer.isSpectator()) { this.getInventory().replaceWith(oldPlayer.getInventory()); this.experienceLevel = oldPlayer.experienceLevel; -@@ -1696,7 +2104,7 @@ +@@ -1696,7 +2103,7 @@ this.lastSentExp = -1; this.lastSentHealth = -1.0F; this.lastSentFood = -1; @@ -1161,7 +1162,7 @@ this.seenCredits = oldPlayer.seenCredits; this.enteredNetherPosition = oldPlayer.enteredNetherPosition; this.chunkTrackingView = oldPlayer.chunkTrackingView; -@@ -1752,19 +2160,19 @@ +@@ -1752,19 +2159,19 @@ } @Override @@ -1185,7 +1186,22 @@ } return flag1; -@@ -1878,6 +2286,16 @@ +@@ -1861,8 +2268,13 @@ + } + + public void sendChatMessage(OutgoingChatMessage message, boolean filterMaskEnabled, ChatType.Bound params) { ++ // Paper start ++ this.sendChatMessage(message, filterMaskEnabled, params, null); ++ } ++ public void sendChatMessage(OutgoingChatMessage message, boolean filterMaskEnabled, ChatType.Bound params, @Nullable Component unsigned) { ++ // Paper end + if (this.acceptsChatMessages()) { +- message.sendToPlayer(this, filterMaskEnabled, params); ++ message.sendToPlayer(this, filterMaskEnabled, params, unsigned); // Paper + } + + } +@@ -1878,7 +2290,18 @@ } public void updateOptions(ClientInformation clientOptions) { @@ -1200,9 +1216,11 @@ + } + // CraftBukkit end this.language = clientOptions.language(); ++ this.adventure$locale = java.util.Objects.requireNonNullElse(net.kyori.adventure.translation.Translator.parseLocale(this.language), java.util.Locale.US); // Paper this.requestedViewDistance = clientOptions.viewDistance(); this.chatVisibility = clientOptions.chatVisibility(); -@@ -1962,7 +2380,7 @@ + this.canChatColor = clientOptions.chatColors(); +@@ -1962,7 +2385,7 @@ if (world instanceof ServerLevel) { ServerLevel worldserver = (ServerLevel) world; @@ -1211,7 +1229,7 @@ } if (entity != null) { -@@ -1999,11 +2417,11 @@ +@@ -1999,11 +2422,11 @@ @Nullable public Component getTabListDisplayName() { @@ -1225,7 +1243,7 @@ } @Override -@@ -2046,17 +2464,43 @@ +@@ -2046,17 +2469,43 @@ } public void setRespawnPosition(ResourceKey dimension, @Nullable BlockPos pos, float angle, boolean forced, boolean sendMessage) { @@ -1276,7 +1294,7 @@ } else { this.respawnPosition = null; this.respawnDimension = Level.OVERWORLD; -@@ -2088,18 +2532,44 @@ +@@ -2088,18 +2537,44 @@ } @Override @@ -1325,7 +1343,7 @@ } this.awardStat(Stats.DROP); -@@ -2375,16 +2845,160 @@ +@@ -2375,10 +2850,12 @@ return TicketType.ENDER_PEARL.timeout(); } @@ -1341,11 +1359,10 @@ } private static float calculateLookAtYaw(Vec3 respawnPos, BlockPos currentPos) { - Vec3 vec3d1 = Vec3.atBottomCenterOf(currentPos).subtract(respawnPos).normalize(); - +@@ -2387,4 +2864,146 @@ return (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D); -+ } -+ } + } + } + + // CraftBukkit start - Add per-player time and weather. + public long timeOffset = 0; @@ -1358,8 +1375,8 @@ + } else { + // Adds timeOffset to the beginning of this day. + return this.level().getDayTime() - (this.level().getDayTime() % 24000) + this.timeOffset; - } - } ++ } ++ } + + public WeatherType weather = null; + diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch index 1d340b8b3e..92119eadac 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerCommonPacketListenerImpl.java.patch @@ -14,7 +14,7 @@ import net.minecraft.network.DisconnectionDetails; import net.minecraft.network.PacketSendListener; import net.minecraft.network.chat.Component; -@@ -22,15 +24,49 @@ +@@ -22,22 +24,56 @@ import net.minecraft.network.protocol.common.ServerboundPongPacket; import net.minecraft.network.protocol.common.ServerboundResourcePackPacket; import net.minecraft.network.protocol.cookie.ServerboundCookieResponsePacket; @@ -65,9 +65,19 @@ private static final Logger LOGGER = LogUtils.getLogger(); public static final int LATENCY_CHECK_INTERVAL = 15000; private static final int CLOSED_LISTENER_TIMEOUT = 15000; -@@ -47,14 +83,26 @@ + private static final Component TIMEOUT_DISCONNECTION_MESSAGE = Component.translatable("disconnect.timeout"); + static final Component DISCONNECT_UNEXPECTED_QUERY = Component.translatable("multiplayer.disconnect.unexpected_query_response"); + protected final MinecraftServer server; +- protected final Connection connection; ++ public final Connection connection; // Paper + private final boolean transferred; + private long keepAliveTime; + private boolean keepAlivePending; +@@ -46,15 +82,28 @@ + private boolean closed = false; private int latency; private volatile boolean suspendFlushingOnServerThread = false; ++ public final java.util.Map packCallbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Paper - adventure resource pack callbacks - public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie clientData) { - this.server = server; @@ -97,7 +107,7 @@ private void close() { if (!this.closed) { this.closedListenerTime = Util.getMillis(); -@@ -80,6 +128,7 @@ +@@ -80,6 +129,7 @@ @Override public void handleKeepAlive(ServerboundKeepAlivePacket packet) { @@ -105,7 +115,7 @@ if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) { int i = (int) (Util.getMillis() - this.keepAliveTime); -@@ -94,9 +143,57 @@ +@@ -94,9 +144,57 @@ @Override public void handlePong(ServerboundPongPacket packet) {} @@ -122,7 +132,7 @@ + PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); + ResourceLocation identifier = packet.payload().type().id(); + ByteBuf payload = ((DiscardedPayload)packet.payload()).data(); -+ + + if (identifier.equals(ServerCommonPacketListenerImpl.CUSTOM_REGISTER)) { + try { + String channels = payload.toString(com.google.common.base.Charsets.UTF_8); @@ -153,7 +163,7 @@ + this.disconnect(Component.literal("Invalid custom payload!")); + } + } - ++ + } + + public final boolean isDisconnected() { @@ -164,10 +174,22 @@ @Override public void handleResourcePackResponse(ServerboundResourcePackPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, (BlockableEventLoop) this.server); -@@ -104,11 +201,18 @@ +@@ -104,11 +202,30 @@ ServerCommonPacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack {} rejection", this.playerProfile().getName(), packet.id()); this.disconnect((Component) Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); } ++ // Paper start - adventure pack callbacks ++ // call the callbacks before the previously-existing event so the event has final say ++ final net.kyori.adventure.resource.ResourcePackCallback callback; ++ if (packet.action().isTerminal()) { ++ callback = this.packCallbacks.remove(packet.id()); ++ } else { ++ callback = this.packCallbacks.get(packet.id()); ++ } ++ if (callback != null) { ++ callback.packEventReceived(packet.id(), net.kyori.adventure.resource.ResourcePackStatus.valueOf(packet.action().name()), this.getCraftPlayer()); ++ } ++ // Paper end + this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(this.getCraftPlayer(), packet.id(), PlayerResourcePackStatusEvent.Status.values()[packet.action().ordinal()])); // CraftBukkit } @@ -183,7 +205,7 @@ this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY); } -@@ -116,7 +220,7 @@ +@@ -116,7 +233,7 @@ Profiler.get().push("keepAlive"); long i = Util.getMillis(); @@ -192,7 +214,7 @@ if (this.keepAlivePending) { this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE); } else if (this.checkIfClosed(i)) { -@@ -156,6 +260,14 @@ +@@ -156,6 +273,14 @@ } public void send(Packet packet, @Nullable PacketSendListener callbacks) { @@ -207,7 +229,18 @@ if (packet.isTerminal()) { this.close(); } -@@ -180,15 +292,61 @@ +@@ -175,20 +300,72 @@ + } + } + ++ // Paper start - adventure ++ public void disconnect(final net.kyori.adventure.text.Component reason) { ++ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(reason)); ++ } ++ // Paper end - adventure ++ + public void disconnect(Component reason) { + this.disconnect(new DisconnectionDetails(reason)); } public void disconnect(DisconnectionDetails disconnectionInfo) { @@ -238,9 +271,9 @@ + return; + } + -+ String leaveMessage = ChatFormatting.YELLOW + this.player.getScoreboardName() + " left the game."; ++ net.kyori.adventure.text.Component leaveMessage = net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? this.player.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(this.player.getScoreboardName())); // Paper - Adventure + -+ PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), CraftChatMessage.fromComponent(disconnectionInfo.reason()), leaveMessage); ++ PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(disconnectionInfo.reason()), leaveMessage); // Paper - adventure + + if (this.cserver.getServer().isRunning()) { + this.cserver.getPluginManager().callEvent(event); @@ -252,7 +285,7 @@ + } + this.player.kickLeaveMessage = event.getLeaveMessage(); // CraftBukkit - SPIGOT-3034: Forward leave message to PlayerQuitEvent + // Send the possibly modified leave message -+ this.disconnect0(new DisconnectionDetails(CraftChatMessage.fromString(event.getReason(), true)[0], disconnectionInfo.report(), disconnectionInfo.bugReportLink())); ++ this.disconnect0(new DisconnectionDetails(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.reason()), disconnectionInfo.report(), disconnectionInfo.bugReportLink())); // Paper - Adventure + } + + private void disconnect0(DisconnectionDetails disconnectiondetails) { diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch index 15355bcb31..81838f6e80 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java.patch @@ -42,7 +42,15 @@ if (!serverlinks.isEmpty()) { this.send(new ClientboundServerLinksPacket(serverlinks.untrust())); -@@ -143,14 +156,14 @@ +@@ -107,6 +120,7 @@ + @Override + public void handleClientInformation(ServerboundClientInformationPacket packet) { + this.clientInformation = packet.information(); ++ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper + } + + @Override +@@ -143,14 +157,14 @@ return; } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index f00c119eb6..10cf991795 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -1,6 +1,14 @@ --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -65,12 +65,15 @@ +@@ -45,6 +45,7 @@ + import net.minecraft.network.Connection; + import net.minecraft.network.DisconnectionDetails; + import net.minecraft.network.TickablePacketListener; ++import net.minecraft.network.chat.ChatDecorator; + import net.minecraft.network.chat.ChatType; + import net.minecraft.network.chat.Component; + import net.minecraft.network.chat.LastSeenMessages; +@@ -65,12 +66,15 @@ import net.minecraft.network.protocol.game.ClientboundBlockChangedAckPacket; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundCommandSuggestionsPacket; @@ -16,7 +24,7 @@ import net.minecraft.network.protocol.game.ClientboundSetHeldSlotPacket; import net.minecraft.network.protocol.game.ClientboundStartConfigurationPacket; import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; -@@ -148,14 +151,13 @@ +@@ -148,14 +152,13 @@ import net.minecraft.world.entity.ExperienceOrb; import net.minecraft.world.entity.HasCustomInventoryScreen; import net.minecraft.world.entity.LivingEntity; @@ -32,7 +40,7 @@ import net.minecraft.world.entity.player.PlayerModelPart; import net.minecraft.world.entity.player.ProfilePublicKey; import net.minecraft.world.entity.projectile.AbstractArrow; -@@ -176,6 +178,7 @@ +@@ -176,6 +179,7 @@ import net.minecraft.world.item.crafting.RecipeHolder; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.level.BaseCommandBlock; @@ -40,7 +48,7 @@ import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; -@@ -192,12 +195,70 @@ +@@ -192,11 +196,71 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; @@ -50,8 +58,10 @@ import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import org.slf4j.Logger; - ++ +// CraftBukkit start ++import io.papermc.paper.adventure.ChatProcessor; // Paper ++import io.papermc.paper.adventure.PaperAdventure; // Paper +import com.mojang.datafixers.util.Pair; +import java.util.Arrays; +import java.util.concurrent.ExecutionException; @@ -107,11 +117,10 @@ +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.SmithingInventory; +// CraftBukkit end -+ + public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl implements ServerGamePacketListener, ServerPlayerConnection, TickablePacketListener { - static final Logger LOGGER = LogUtils.getLogger(); -@@ -247,7 +308,7 @@ +@@ -247,7 +311,7 @@ private boolean waitingForSwitchToConfig; public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie clientData) { @@ -120,14 +129,14 @@ this.chunkSender = new PlayerChunkSender(connection.isMemoryConnection()); this.player = player; player.connection = this; -@@ -256,11 +317,28 @@ +@@ -256,11 +320,28 @@ Objects.requireNonNull(server); this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(uuid, server::enforceSecureProfile); - this.chatMessageChain = new FutureChain(server); + this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat } -+ + + // CraftBukkit start - add fields and methods + private int lastTick = MinecraftServer.currentTick; + private int allowedPlayerTicks = 1; @@ -143,14 +152,14 @@ + private float lastYaw = Float.MAX_VALUE; + private boolean justTeleported = false; + // CraftBukkit end - ++ @Override public void tick() { + org.bukkit.craftbukkit.SpigotTimings.playerConnectionTimer.startTiming(); // Spigot if (this.ackBlockChangesUpTo > -1) { this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); this.ackBlockChangesUpTo = -1; -@@ -313,8 +391,10 @@ +@@ -313,8 +394,10 @@ this.chatSpamThrottler.tick(); this.dropSpamThrottler.tick(); if (this.player.getLastActionTime() > 0L && this.server.getPlayerIdleTimeout() > 0 && Util.getMillis() - this.player.getLastActionTime() > (long) this.server.getPlayerIdleTimeout() * 1000L * 60L) { @@ -161,7 +170,7 @@ } -@@ -376,6 +456,12 @@ +@@ -376,6 +459,12 @@ @Override public void handlePlayerInput(ServerboundPlayerInputPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -174,7 +183,7 @@ this.player.setLastClientInput(packet.input()); } -@@ -401,6 +487,13 @@ +@@ -401,6 +490,13 @@ if (entity != this.player && entity.getControllingPassenger() == this.player && entity == this.lastVehicle) { ServerLevel worldserver = this.player.serverLevel(); @@ -188,7 +197,7 @@ double d0 = entity.getX(); double d1 = entity.getY(); double d2 = entity.getZ(); -@@ -415,7 +508,33 @@ +@@ -415,7 +511,33 @@ double d9 = entity.getDeltaMovement().lengthSqr(); double d10 = d6 * d6 + d7 * d7 + d8 * d8; @@ -223,7 +232,7 @@ ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved too quickly! {},{},{}", new Object[]{entity.getName().getString(), this.player.getName().getString(), d6, d7, d8}); this.send(ClientboundMoveVehiclePacket.fromEntity(entity)); return; -@@ -449,19 +568,72 @@ +@@ -449,19 +571,72 @@ d10 = d6 * d6 + d7 * d7 + d8 * d8; boolean flag2 = false; @@ -297,7 +306,7 @@ this.player.serverLevel().getChunkSource().move(this.player); entity.recordMovementThroughBlocks(new Vec3(d0, d1, d2), entity.position()); -@@ -499,6 +671,7 @@ +@@ -499,6 +674,7 @@ this.lastGoodZ = this.awaitingPositionFromClient.z; this.player.hasChangedDimension(); this.awaitingPositionFromClient = null; @@ -305,7 +314,7 @@ } } -@@ -528,6 +701,7 @@ +@@ -528,6 +704,7 @@ @Override public void handleRecipeBookChangeSettingsPacket(ServerboundRecipeBookChangeSettingsPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -313,7 +322,7 @@ this.player.getRecipeBook().setBookSetting(packet.getBookType(), packet.isOpen(), packet.isFiltering()); } -@@ -548,6 +722,12 @@ +@@ -548,6 +725,12 @@ @Override public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -326,7 +335,7 @@ StringReader stringreader = new StringReader(packet.getCommand()); if (stringreader.canRead() && stringreader.peek() == '/') { -@@ -557,6 +737,7 @@ +@@ -557,6 +740,7 @@ ParseResults parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack()); this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> { @@ -334,7 +343,7 @@ Suggestions suggestions1 = suggestions.getList().size() <= 1000 ? suggestions : new Suggestions(suggestions.getRange(), suggestions.getList().subList(0, 1000)); this.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions1)); -@@ -668,7 +849,7 @@ +@@ -668,7 +852,7 @@ ItemStack itemstack = iblockdata.getCloneItemStack(worldserver, blockposition, flag); if (!itemstack.isEmpty()) { @@ -343,7 +352,7 @@ ServerGamePacketListenerImpl.addBlockDataToItem(iblockdata, worldserver, blockposition, itemstack); } -@@ -866,6 +1047,13 @@ +@@ -866,6 +1050,13 @@ AbstractContainerMenu container = this.player.containerMenu; if (container instanceof MerchantMenu containermerchant) { @@ -357,7 +366,7 @@ if (!containermerchant.stillValid(this.player)) { ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, containermerchant); return; -@@ -879,6 +1067,13 @@ +@@ -879,6 +1070,13 @@ @Override public void handleEditBook(ServerboundEditBookPacket packet) { @@ -371,7 +380,7 @@ int i = packet.slot(); if (Inventory.isHotbarSlot(i) || i == 40) { -@@ -899,12 +1094,16 @@ +@@ -899,12 +1097,16 @@ } private void updateBookContents(List pages, int slotId) { @@ -389,7 +398,7 @@ } } -@@ -915,12 +1114,13 @@ +@@ -915,12 +1117,13 @@ ItemStack itemstack1 = itemstack.transmuteCopy(Items.WRITTEN_BOOK); itemstack1.remove(DataComponents.WRITABLE_BOOK_CONTENT); @@ -405,7 +414,7 @@ } } -@@ -982,7 +1182,7 @@ +@@ -982,7 +1185,7 @@ } else { ServerLevel worldserver = this.player.serverLevel(); @@ -414,7 +423,7 @@ if (this.tickCount == 0) { this.resetPosition(); } -@@ -997,7 +1197,15 @@ +@@ -997,7 +1200,15 @@ if (this.player.isPassenger()) { this.player.absMoveTo(this.player.getX(), this.player.getY(), this.player.getZ(), f, f1); this.player.serverLevel().getChunkSource().move(this.player); @@ -430,7 +439,7 @@ double d3 = this.player.getX(); double d4 = this.player.getY(); double d5 = this.player.getZ(); -@@ -1019,15 +1227,33 @@ +@@ -1019,15 +1230,33 @@ ++this.receivedMovePacketCount; int i = this.receivedMovePacketCount - this.knownMovePacketCount; @@ -443,20 +452,20 @@ + if (i > Math.max(this.allowedPlayerTicks, 5)) { ServerGamePacketListenerImpl.LOGGER.debug("{} is sending move packets too frequently ({} packets since last tick)", this.player.getName().getString(), i); i = 1; - } - ++ } ++ + if (packet.hasRot || d10 > 0) { + this.allowedPlayerTicks -= 1; + } else { + this.allowedPlayerTicks = 20; -+ } + } + double speed; + if (this.player.getAbilities().flying) { + speed = this.player.getAbilities().flyingSpeed * 20f; + } else { + speed = this.player.getAbilities().walkingSpeed * 10f; + } -+ + if (this.shouldCheckPlayerMovement(flag)) { float f2 = flag ? 300.0F : 100.0F; @@ -466,7 +475,7 @@ ServerGamePacketListenerImpl.LOGGER.warn("{} moved too quickly! {},{},{}", new Object[]{this.player.getName().getString(), d6, d7, d8}); this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()); return; -@@ -1049,6 +1275,7 @@ +@@ -1049,6 +1278,7 @@ boolean flag2 = this.player.verticalCollisionBelow; this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8)); @@ -474,7 +483,7 @@ double d11 = d7; d6 = d0 - this.player.getX(); -@@ -1061,15 +1288,81 @@ +@@ -1061,15 +1291,81 @@ d10 = d6 * d6 + d7 * d7 + d8 * d8; boolean flag3 = false; @@ -558,7 +567,7 @@ this.player.absMoveTo(d0, d1, d2, f, f1); boolean flag4 = this.player.isAutoSpinAttack(); -@@ -1119,6 +1412,7 @@ +@@ -1119,6 +1415,7 @@ this.awaitingTeleportTime = this.tickCount; this.teleport(this.awaitingPositionFromClient.x, this.awaitingPositionFromClient.y, this.awaitingPositionFromClient.z, this.player.getYRot(), this.player.getXRot()); } @@ -566,7 +575,7 @@ return true; } else { -@@ -1147,23 +1441,83 @@ +@@ -1147,23 +1444,83 @@ } public void teleport(double x, double y, double z, float yaw, float pitch) { @@ -653,7 +662,7 @@ if (this.player.hasClientLoaded()) { BlockPos blockposition = packet.getPos(); -@@ -1175,14 +1529,46 @@ +@@ -1175,14 +1532,46 @@ if (!this.player.isSpectator()) { ItemStack itemstack = this.player.getItemInHand(InteractionHand.OFF_HAND); @@ -702,7 +711,7 @@ this.player.drop(false); } -@@ -1218,9 +1604,30 @@ +@@ -1218,9 +1607,30 @@ } } @@ -733,7 +742,7 @@ if (this.player.hasClientLoaded()) { this.player.connection.ackBlockChangesUpTo(packet.getSequence()); ServerLevel worldserver = this.player.serverLevel(); -@@ -1244,6 +1651,7 @@ +@@ -1244,6 +1654,7 @@ if (blockposition.getY() <= i) { if (this.awaitingPositionFromClient == null && worldserver.mayInteract(this.player, blockposition)) { @@ -741,7 +750,7 @@ InteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock); if (enuminteractionresult.consumesAction()) { -@@ -1281,6 +1689,8 @@ +@@ -1281,6 +1692,8 @@ @Override public void handleUseItem(ServerboundUseItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -750,7 +759,7 @@ if (this.player.hasClientLoaded()) { this.ackBlockChangesUpTo(packet.getSequence()); ServerLevel worldserver = this.player.serverLevel(); -@@ -1296,6 +1706,47 @@ +@@ -1296,6 +1709,47 @@ this.player.absRotateTo(f, f1); } @@ -798,7 +807,7 @@ InteractionResult enuminteractionresult = this.player.gameMode.useItem(this.player, worldserver, itemstack, enumhand); if (enuminteractionresult instanceof InteractionResult.Success) { -@@ -1321,7 +1772,7 @@ +@@ -1321,7 +1775,7 @@ Entity entity = packet.getEntity(worldserver); if (entity != null) { @@ -807,7 +816,7 @@ return; } } -@@ -1342,6 +1793,13 @@ +@@ -1342,6 +1796,13 @@ @Override public void onDisconnect(DisconnectionDetails info) { @@ -821,7 +830,7 @@ ServerGamePacketListenerImpl.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), info.reason().getString()); this.removePlayerFromWorld(); super.onDisconnect(info); -@@ -1349,10 +1807,18 @@ +@@ -1349,10 +1810,20 @@ private void removePlayerFromWorld() { this.chatMessageChain.close(); @@ -834,15 +843,17 @@ + this.player.disconnect(); - this.server.getPlayerList().remove(this.player); -+ String quitMessage = this.server.getPlayerList().remove(this.player); -+ if ((quitMessage != null) && (quitMessage.length() > 0)) { -+ this.server.getPlayerList().broadcastMessage(CraftChatMessage.fromString(quitMessage)); ++ // Paper start - Adventure ++ net.kyori.adventure.text.Component quitMessage = this.server.getPlayerList().remove(this.player); ++ if ((quitMessage != null) && !quitMessage.equals(net.kyori.adventure.text.Component.empty())) { ++ this.server.getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(quitMessage), false); ++ // Paper end + } + // CraftBukkit end this.player.getTextFilter().leave(); } -@@ -1367,7 +1833,16 @@ +@@ -1367,7 +1838,16 @@ @Override public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -859,7 +870,7 @@ if (this.player.getInventory().selected != packet.getSlot() && this.player.getUsedItemHand() == InteractionHand.MAIN_HAND) { this.player.stopUsingItem(); } -@@ -1376,11 +1851,18 @@ +@@ -1376,11 +1856,18 @@ this.player.resetLastActionTime(); } else { ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString()); @@ -878,16 +889,19 @@ Optional optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); if (!optional.isEmpty()) { -@@ -1394,7 +1876,7 @@ +@@ -1394,27 +1881,44 @@ return; } - CompletableFuture completablefuture = this.filterTextPacket(playerchatmessage.signedContent()); +- Component ichatbasecomponent = this.server.getChatDecorator().decorate(this.player, playerchatmessage.decoratedContent()); + CompletableFuture completablefuture = this.filterTextPacket(playerchatmessage.signedContent()).thenApplyAsync(Function.identity(), this.server.chatExecutor); // CraftBukkit - async chat - Component ichatbasecomponent = this.server.getChatDecorator().decorate(this.player, playerchatmessage.decoratedContent()); ++ CompletableFuture componentFuture = this.server.getChatDecorator().decorate(this.player, null, playerchatmessage.decoratedContent()); // Paper - Adventure - this.chatMessageChain.append(completablefuture, (filteredtext) -> { -@@ -1402,19 +1884,36 @@ +- this.chatMessageChain.append(completablefuture, (filteredtext) -> { +- PlayerChatMessage playerchatmessage1 = playerchatmessage.withUnsignedContent(ichatbasecomponent).filter(filteredtext.mask()); ++ this.chatMessageChain.append(CompletableFuture.allOf(completablefuture, componentFuture), (filteredtext) -> { // Paper - Adventure ++ PlayerChatMessage playerchatmessage1 = playerchatmessage.withUnsignedContent(componentFuture.join()).filter(completablefuture.join().mask()); // Paper - Adventure this.broadcastChatMessage(playerchatmessage1); }); @@ -927,7 +941,7 @@ ParseResults parseresults = this.parseCommand(command); if (this.server.enforceSecureProfile() && SignableCommand.hasSignableArguments(parseresults)) { -@@ -1431,19 +1930,37 @@ +@@ -1431,19 +1935,37 @@ if (!optional.isEmpty()) { this.tryHandleChat(packet.command(), () -> { @@ -969,7 +983,7 @@ } catch (SignedMessageChain.DecodeException signedmessagechain_a) { this.handleMessageDecodeFailure(signedmessagechain_a); return; -@@ -1451,10 +1968,10 @@ +@@ -1451,10 +1973,10 @@ CommandSigningContext.SignedArguments commandsigningcontext_a = new CommandSigningContext.SignedArguments(map); @@ -982,7 +996,7 @@ } private void handleMessageDecodeFailure(SignedMessageChain.DecodeException exception) { -@@ -1530,14 +2047,20 @@ +@@ -1530,14 +2052,20 @@ return com_mojang_brigadier_commanddispatcher.parse(command, this.player.createCommandSourceStack()); } @@ -1007,7 +1021,7 @@ } } -@@ -1566,6 +2089,121 @@ +@@ -1566,6 +2094,129 @@ return false; } @@ -1022,7 +1036,15 @@ + this.handleCommand(s); + } else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) { + // Do nothing, this is coming from a plugin -+ } else { ++ // Paper start ++ } else if (true) { ++ if (!async && !org.bukkit.Bukkit.isPrimaryThread()) { ++ org.spigotmc.AsyncCatcher.catchOp("Asynchronous player chat is not allowed here"); ++ } ++ final ChatProcessor cp = new ChatProcessor(this.server, this.player, original, async); ++ cp.process(); ++ // Paper end ++ } else if (false) { // Paper + Player player = this.getCraftPlayer(); + AsyncPlayerChatEvent event = new AsyncPlayerChatEvent(async, player, s, new LazyPlayerSet(this.server)); + String originalFormat = event.getFormat(), originalMessage = event.getMessage(); @@ -1129,7 +1151,7 @@ private PlayerChatMessage getSignedMessage(ServerboundChatPacket packet, LastSeenMessages lastSeenMessages) throws SignedMessageChain.DecodeException { SignedMessageBody signedmessagebody = new SignedMessageBody(packet.message(), packet.timeStamp(), packet.salt(), lastSeenMessages); -@@ -1573,13 +2211,42 @@ +@@ -1573,13 +2224,42 @@ } private void broadcastChatMessage(PlayerChatMessage message) { @@ -1177,7 +1199,7 @@ this.disconnect((Component) Component.translatable("disconnect.spam")); } -@@ -1601,7 +2268,33 @@ +@@ -1601,7 +2281,33 @@ @Override public void handleAnimate(ServerboundSwingPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1211,7 +1233,7 @@ this.player.swing(packet.getHand()); } -@@ -1609,6 +2302,29 @@ +@@ -1609,6 +2315,29 @@ public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); if (this.player.hasClientLoaded()) { @@ -1241,7 +1263,7 @@ this.player.resetLastActionTime(); Entity entity; PlayerRideableJumping ijumpable; -@@ -1691,6 +2407,12 @@ +@@ -1691,6 +2420,12 @@ } public void sendPlayerChatMessage(PlayerChatMessage message, ChatType.Bound params) { @@ -1254,7 +1276,7 @@ this.send(new ClientboundPlayerChatPacket(message.link().sender(), message.link().index(), message.signature(), message.signedBody().pack(this.messageSignatureCache), message.unsignedContent(), message.filterMask(), params)); this.addPendingMessage(message); } -@@ -1703,6 +2425,13 @@ +@@ -1703,6 +2438,13 @@ return this.connection.getRemoteAddress(); } @@ -1268,7 +1290,7 @@ public void switchToConfig() { this.waitingForSwitchToConfig = true; this.removePlayerFromWorld(); -@@ -1718,9 +2447,17 @@ +@@ -1718,9 +2460,17 @@ @Override public void handleInteract(ServerboundInteractPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1286,7 +1308,7 @@ this.player.resetLastActionTime(); this.player.setShiftKeyDown(packet.isUsingSecondaryAction()); -@@ -1733,20 +2470,58 @@ +@@ -1733,20 +2483,58 @@ if (this.player.canInteractWithEntity(axisalignedbb, 3.0D)) { packet.dispatch(new ServerboundInteractPacket.Handler() { @@ -1302,7 +1324,7 @@ + ItemStack itemInHand = ServerGamePacketListenerImpl.this.player.getItemInHand(enumhand); + boolean triggerLeashUpdate = itemInHand != null && itemInHand.getItem() == Items.LEAD && entity instanceof Mob; + Item origItem = ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null ? null : ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem(); - ++ + ServerGamePacketListenerImpl.this.cserver.getPluginManager().callEvent(event); + + // Entity in bucket - SPIGOT-4048 and SPIGOT-6859a @@ -1331,7 +1353,7 @@ + } + // CraftBukkit end + InteractionResult enuminteractionresult = playerconnection_a.run(ServerGamePacketListenerImpl.this.player, entity, enumhand); -+ + + // CraftBukkit start + if (!itemInHand.isEmpty() && itemInHand.getCount() <= -1) { + ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); @@ -1349,7 +1371,7 @@ } } -@@ -1755,19 +2530,20 @@ +@@ -1755,19 +2543,20 @@ @Override public void onInteraction(InteractionHand hand) { @@ -1373,7 +1395,7 @@ label23: { if (entity instanceof AbstractArrow) { -@@ -1785,6 +2561,11 @@ +@@ -1785,6 +2574,11 @@ } ServerGamePacketListenerImpl.this.player.attack(entity); @@ -1385,7 +1407,7 @@ return; } } -@@ -1809,7 +2590,7 @@ +@@ -1809,7 +2603,7 @@ case PERFORM_RESPAWN: if (this.player.wonGame) { this.player.wonGame = false; @@ -1394,7 +1416,7 @@ this.resetPosition(); CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, Level.END, Level.OVERWORLD); } else { -@@ -1817,11 +2598,11 @@ +@@ -1817,11 +2611,11 @@ return; } @@ -1408,7 +1430,7 @@ } } break; -@@ -1834,15 +2615,21 @@ +@@ -1834,15 +2628,21 @@ @Override public void handleContainerClose(ServerboundContainerClosePacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1432,7 +1454,7 @@ this.player.containerMenu.sendAllDataToRemote(); } else if (!this.player.containerMenu.stillValid(this.player)) { ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu); -@@ -1855,7 +2642,284 @@ +@@ -1855,7 +2655,284 @@ boolean flag = packet.getStateId() != this.player.containerMenu.getStateId(); this.player.containerMenu.suppressRemoteUpdates(); @@ -1718,7 +1740,7 @@ ObjectIterator objectiterator = Int2ObjectMaps.fastIterable(packet.getChangedSlots()).iterator(); while (objectiterator.hasNext()) { -@@ -1901,8 +2965,22 @@ +@@ -1901,8 +2978,22 @@ return; } @@ -1742,7 +1764,7 @@ if (containerrecipebook_a == RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE) { this.player.connection.send(new ClientboundPlaceGhostRecipePacket(this.player.containerMenu.containerId, craftingmanager_d.display().display())); } -@@ -1917,6 +2995,7 @@ +@@ -1917,6 +3008,7 @@ @Override public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1750,7 +1772,7 @@ this.player.resetLastActionTime(); if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) { if (!this.player.containerMenu.stillValid(this.player)) { -@@ -1945,7 +3024,44 @@ +@@ -1945,6 +3037,43 @@ boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45; boolean flag2 = itemstack.isEmpty() || itemstack.getCount() <= itemstack.getMaxStackSize(); @@ -1758,7 +1780,7 @@ + // CraftBukkit start - Call click event + InventoryView inventory = this.player.inventoryMenu.getBukkitView(); + org.bukkit.inventory.ItemStack item = CraftItemStack.asBukkitCopy(packet.itemStack()); - ++ + SlotType type = SlotType.QUICKBAR; + if (flag) { + type = SlotType.OUTSIDE; @@ -1791,11 +1813,10 @@ + } + } + // CraftBukkit end -+ + if (flag1 && flag2) { this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemstack); - this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemstack); -@@ -1972,6 +3088,7 @@ +@@ -1972,6 +3101,7 @@ } private void updateSignText(ServerboundSignUpdatePacket packet, List signText) { @@ -1803,7 +1824,7 @@ this.player.resetLastActionTime(); ServerLevel worldserver = this.player.serverLevel(); BlockPos blockposition = packet.getPos(); -@@ -1993,7 +3110,17 @@ +@@ -1993,7 +3123,17 @@ @Override public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1822,7 +1843,15 @@ } @Override -@@ -2058,7 +3185,7 @@ +@@ -2002,6 +3142,7 @@ + boolean flag = this.player.isModelPartShown(PlayerModelPart.HAT); + + this.player.updateOptions(packet.information()); ++ this.connection.channel.attr(io.papermc.paper.adventure.PaperAdventure.LOCALE_ATTRIBUTE).set(net.kyori.adventure.translation.Translator.parseLocale(packet.information().language())); // Paper + if (this.player.isModelPartShown(PlayerModelPart.HAT) != flag) { + this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player)); + } +@@ -2058,7 +3199,7 @@ if (!this.waitingForSwitchToConfig) { throw new IllegalStateException("Client acknowledged config, but none was requested"); } else { @@ -1831,7 +1860,7 @@ } } -@@ -2083,8 +3210,10 @@ +@@ -2083,8 +3224,10 @@ }); } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch index dbae921f04..ff06f6ab0f 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch @@ -214,7 +214,7 @@ + if (PlayerPreLoginEvent.getHandlerList().getRegisteredListeners().length != 0) { + final PlayerPreLoginEvent event = new PlayerPreLoginEvent(playerName, address, uniqueId); + if (asyncEvent.getResult() != PlayerPreLoginEvent.Result.ALLOWED) { -+ event.disallow(asyncEvent.getResult(), asyncEvent.getKickMessage()); ++ event.disallow(asyncEvent.getResult(), asyncEvent.kickMessage()); // Paper - Adventure + } + Waitable waitable = new Waitable() { + @Override @@ -226,12 +226,12 @@ + + ServerLoginPacketListenerImpl.this.server.processQueue.add(waitable); + if (waitable.get() != PlayerPreLoginEvent.Result.ALLOWED) { -+ this.disconnect(event.getKickMessage()); ++ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.kickMessage())); // Paper - Adventure + return; + } + } else { + if (asyncEvent.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) { -+ this.disconnect(asyncEvent.getKickMessage()); ++ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(asyncEvent.kickMessage())); // Paper - Adventure + return; + } + } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch index 8acb1e18bc..eda30ce038 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerStatusPacketListenerImpl.java.patch @@ -34,7 +34,7 @@ + CraftIconCache icon = server.server.getServerIcon(); + + ServerListPingEvent() { -+ super(ServerStatusPacketListenerImpl.this.connection.hostname, ((InetSocketAddress) ServerStatusPacketListenerImpl.this.connection.getRemoteAddress()).getAddress(), server.getMotd(), server.getPlayerList().getMaxPlayers()); ++ super(ServerStatusPacketListenerImpl.this.connection.hostname, ((InetSocketAddress) ServerStatusPacketListenerImpl.this.connection.getRemoteAddress()).getAddress(), server.server.motd(), server.getPlayerList().getMaxPlayers()); // Paper - Adventure + } + + @Override diff --git a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch index f22c600df0..1a2bf36881 100644 --- a/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/players/PlayerList.java.patch @@ -177,13 +177,13 @@ } + // CraftBukkit start + ichatmutablecomponent.withStyle(ChatFormatting.YELLOW); -+ String joinMessage = CraftChatMessage.fromComponent(ichatmutablecomponent); ++ Component joinMessage = ichatmutablecomponent; // Paper - Adventure - this.broadcastSystemMessage(ichatmutablecomponent.withStyle(ChatFormatting.YELLOW), false); playerconnection.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); ServerStatus serverping = this.server.getStatus(); -@@ -222,17 +283,71 @@ +@@ -222,17 +283,70 @@ player.sendServerStatus(serverping); } @@ -201,19 +201,18 @@ + // Ensure that player inventory is populated with its viewer + player.containerMenu.transferTo(player.containerMenu, bukkitPlayer); + -+ PlayerJoinEvent playerJoinEvent = new PlayerJoinEvent(bukkitPlayer, joinMessage); ++ PlayerJoinEvent playerJoinEvent = new PlayerJoinEvent(bukkitPlayer, io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure + this.cserver.getPluginManager().callEvent(playerJoinEvent); + + if (!player.connection.isAcceptingMessages()) { + return; + } + -+ joinMessage = playerJoinEvent.getJoinMessage(); ++ final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage(); + -+ if (joinMessage != null && joinMessage.length() > 0) { -+ for (Component line : org.bukkit.craftbukkit.util.CraftChatMessage.fromString(joinMessage)) { -+ this.server.getPlayerList().broadcastSystemMessage(line, false); -+ } ++ if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure ++ joinMessage = io.papermc.paper.adventure.PaperAdventure.asVanilla(jm); // Paper - Adventure ++ this.server.getPlayerList().broadcastSystemMessage(joinMessage, false); // Paper - Adventure + } + // CraftBukkit end + @@ -259,7 +258,7 @@ } public void updateEntireScoreboard(ServerScoreboard scoreboard, ServerPlayer player) { -@@ -269,30 +384,31 @@ +@@ -269,30 +383,31 @@ } public void addWorldborderListener(ServerLevel world) { @@ -296,7 +295,7 @@ } @Override -@@ -319,14 +435,15 @@ +@@ -319,14 +434,15 @@ } protected void save(ServerPlayer player) { @@ -314,13 +313,13 @@ if (advancementdataplayer != null) { advancementdataplayer.save(); -@@ -334,95 +451,176 @@ +@@ -334,95 +450,176 @@ } - public void remove(ServerPlayer player) { - ServerLevel worldserver = player.serverLevel(); -+ public String remove(ServerPlayer entityplayer) { // CraftBukkit - return string ++ public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer) { // CraftBukkit - return string // Paper - return Component + ServerLevel worldserver = entityplayer.serverLevel(); - player.awardStat(Stats.LEAVE_GAME); @@ -335,7 +334,7 @@ + entityplayer.closeContainer(); + } + -+ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), entityplayer.kickLeaveMessage != null ? entityplayer.kickLeaveMessage : "\u00A7e" + entityplayer.getScoreboardName() + " left the game"); ++ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName()))); // Paper - Adventure + this.cserver.getPluginManager().callEvent(playerQuitEvent); + entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); + @@ -410,7 +409,7 @@ + this.cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity()); + // CraftBukkit end + -+ return playerQuitEvent.getQuitMessage(); // CraftBukkit ++ return playerQuitEvent.quitMessage(); // Paper - Adventure } - @Nullable @@ -466,11 +465,11 @@ - } else if (this.ipBans.isBanned(address)) { - IpBanListEntry ipbanentry = this.ipBans.get(address); + // return chatmessage; -+ event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(ichatmutablecomponent)); ++ event.disallow(PlayerLoginEvent.Result.KICK_BANNED, io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure + } else if (!this.isWhiteListed(gameprofile)) { + ichatmutablecomponent = Component.translatable("multiplayer.disconnect.not_whitelisted"); -+ event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, org.spigotmc.SpigotConfig.whitelistMessage); // Spigot -+ } else if (this.ipBans.isBanned(socketaddress)) { ++ event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.whitelistMessage)); // Spigot // Paper - Adventure ++ } else if (this.getIpBans().isBanned(socketaddress) && !this.getIpBans().get(socketaddress).hasExpired()) { + IpBanListEntry ipbanentry = this.ipBans.get(socketaddress); ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned_ip.reason", ipbanentry.getReason()); @@ -479,20 +478,19 @@ } - return ichatmutablecomponent; -- } else { -- return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(profile) ? Component.translatable("multiplayer.disconnect.server_full") : null; + // return chatmessage; -+ event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(ichatmutablecomponent)); -+ } else { ++ event.disallow(PlayerLoginEvent.Result.KICK_BANNED, io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure + } else { +- return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(profile) ? Component.translatable("multiplayer.disconnect.server_full") : null; + // return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile) ? IChatBaseComponent.translatable("multiplayer.disconnect.server_full") : null; + if (this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile)) { -+ event.disallow(PlayerLoginEvent.Result.KICK_FULL, org.spigotmc.SpigotConfig.serverFullMessage); // Spigot ++ event.disallow(PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure + } } + + this.cserver.getPluginManager().callEvent(event); + if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) { -+ loginlistener.disconnect(event.getKickMessage()); ++ loginlistener.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.kickMessage())); // Paper - Adventure + return null; + } + return entity; @@ -530,7 +528,7 @@ if (entityplayer1 != null) { set.add(entityplayer1); -@@ -431,30 +629,50 @@ +@@ -431,30 +628,50 @@ Iterator iterator1 = set.iterator(); while (iterator1.hasNext()) { @@ -594,7 +592,7 @@ while (iterator.hasNext()) { String s = (String) iterator.next(); -@@ -462,41 +680,88 @@ +@@ -462,41 +679,88 @@ entityplayer1.addTag(s); } @@ -691,7 +689,7 @@ return entityplayer1; } -@@ -524,7 +789,18 @@ +@@ -524,7 +788,18 @@ public void tick() { if (++this.sendAllPlayerInfoIn > 600) { @@ -711,7 +709,7 @@ this.sendAllPlayerInfoIn = 0; } -@@ -541,6 +817,25 @@ +@@ -541,6 +816,25 @@ } @@ -737,7 +735,7 @@ public void broadcastAll(Packet packet, ResourceKey dimension) { Iterator iterator = this.players.iterator(); -@@ -554,7 +849,7 @@ +@@ -554,7 +848,7 @@ } @@ -746,7 +744,7 @@ PlayerTeam scoreboardteam = source.getTeam(); if (scoreboardteam != null) { -@@ -573,7 +868,7 @@ +@@ -573,7 +867,7 @@ } } @@ -755,7 +753,7 @@ PlayerTeam scoreboardteam = source.getTeam(); if (scoreboardteam == null) { -@@ -619,7 +914,7 @@ +@@ -619,7 +913,7 @@ } public void deop(GameProfile profile) { @@ -764,7 +762,7 @@ ServerPlayer entityplayer = this.getPlayer(profile.getId()); if (entityplayer != null) { -@@ -643,6 +938,7 @@ +@@ -643,6 +937,7 @@ player.connection.send(new ClientboundEntityEventPacket(player, b0)); } @@ -772,7 +770,7 @@ this.server.getCommands().sendCommands(player); } -@@ -656,23 +952,19 @@ +@@ -656,23 +951,19 @@ @Nullable public ServerPlayer getPlayerByName(String name) { @@ -804,7 +802,7 @@ if (entityplayer != player && entityplayer.level().dimension() == worldKey) { double d4 = x - entityplayer.getX(); double d5 = y - entityplayer.getY(); -@@ -712,15 +1004,19 @@ +@@ -712,15 +1003,19 @@ public void reloadWhiteList() {} public void sendLevelInfo(ServerPlayer player, ServerLevel world) { @@ -828,7 +826,7 @@ } player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LEVEL_CHUNKS_LOAD_START, 0.0F)); -@@ -729,8 +1025,16 @@ +@@ -729,8 +1024,16 @@ public void sendAllPlayerInfo(ServerPlayer player) { player.inventoryMenu.sendAllDataToRemote(); @@ -846,7 +844,7 @@ } public int getPlayerCount() { -@@ -786,12 +1090,22 @@ +@@ -786,12 +1089,22 @@ } public void removeAll() { @@ -854,7 +852,7 @@ - ((ServerPlayer) this.players.get(i)).connection.disconnect((Component) Component.translatable("multiplayer.disconnect.server_shutdown")); + // CraftBukkit start - disconnect safely + for (ServerPlayer player : this.players) { -+ player.connection.disconnect(CraftChatMessage.fromStringOrEmpty(this.server.server.getShutdownMessage())); // CraftBukkit - add custom shutdown message ++ player.connection.disconnect(java.util.Objects.requireNonNullElseGet(this.server.server.shutdownMessage(), net.kyori.adventure.text.Component::empty)); // CraftBukkit - add custom shutdown message // Paper - Adventure } + // CraftBukkit end @@ -871,7 +869,59 @@ public void broadcastSystemMessage(Component message, boolean overlay) { this.broadcastSystemMessage(message, (entityplayer) -> { return message; -@@ -849,16 +1163,23 @@ +@@ -819,24 +1132,43 @@ + } + + public void broadcastChatMessage(PlayerChatMessage message, ServerPlayer sender, ChatType.Bound params) { ++ // Paper start ++ this.broadcastChatMessage(message, sender, params, null); ++ } ++ public void broadcastChatMessage(PlayerChatMessage message, ServerPlayer sender, ChatType.Bound params, @Nullable Function unsignedFunction) { ++ // Paper end + Objects.requireNonNull(sender); +- this.broadcastChatMessage(message, sender::shouldFilterMessageTo, sender, params); ++ this.broadcastChatMessage(message, sender::shouldFilterMessageTo, sender, params, unsignedFunction); // Paper + } + + private void broadcastChatMessage(PlayerChatMessage message, Predicate shouldSendFiltered, @Nullable ServerPlayer sender, ChatType.Bound params) { ++ // Paper start ++ this.broadcastChatMessage(message, shouldSendFiltered, sender, params, null); ++ } ++ public void broadcastChatMessage(PlayerChatMessage message, Predicate shouldSendFiltered, @Nullable ServerPlayer sender, ChatType.Bound params, @Nullable Function unsignedFunction) { ++ // Paper end + boolean flag = this.verifyChatTrusted(message); + +- this.server.logChatMessage(message.decoratedContent(), params, flag ? null : "Not Secure"); ++ this.server.logChatMessage((unsignedFunction == null ? message.decoratedContent() : unsignedFunction.apply(this.server.console)), params, flag ? null : "Not Secure"); // Paper + OutgoingChatMessage outgoingchatmessage = OutgoingChatMessage.create(message); + boolean flag1 = false; + + boolean flag2; ++ Packet disguised = sender != null && unsignedFunction == null ? new net.minecraft.network.protocol.game.ClientboundDisguisedChatPacket(outgoingchatmessage.content(), params) : null; // Paper - don't send player chat packets from vanished players + + for (Iterator iterator = this.players.iterator(); iterator.hasNext(); flag1 |= flag2 && message.isFullyFiltered()) { + ServerPlayer entityplayer1 = (ServerPlayer) iterator.next(); + + flag2 = shouldSendFiltered.test(entityplayer1); +- entityplayer1.sendChatMessage(outgoingchatmessage, flag2, params); ++ // Paper start - don't send player chat packets from vanished players ++ if (sender != null && !entityplayer1.getBukkitEntity().canSee(sender.getBukkitEntity())) { ++ entityplayer1.connection.send(unsignedFunction != null ++ ? new net.minecraft.network.protocol.game.ClientboundDisguisedChatPacket(unsignedFunction.apply(entityplayer1.getBukkitEntity()), params) ++ : disguised); ++ continue; ++ } ++ // Paper end ++ entityplayer1.sendChatMessage(outgoingchatmessage, flag2, params, unsignedFunction == null ? null : unsignedFunction.apply(entityplayer1.getBukkitEntity())); // Paper + } + + if (flag1 && sender != null) { +@@ -845,20 +1177,27 @@ + + } + +- private boolean verifyChatTrusted(PlayerChatMessage message) { ++ public boolean verifyChatTrusted(PlayerChatMessage message) { // Paper - private -> public return message.hasSignature() && !message.hasExpiredServer(Instant.now()); } @@ -899,7 +949,7 @@ Path path = file2.toPath(); if (FileUtil.isPathNormalized(path) && FileUtil.isPathPortable(path) && path.startsWith(file.getPath()) && file2.isFile()) { -@@ -867,7 +1188,7 @@ +@@ -867,7 +1206,7 @@ } serverstatisticmanager = new ServerStatsCounter(this.server, file1); @@ -908,7 +958,7 @@ } return serverstatisticmanager; -@@ -875,13 +1196,13 @@ +@@ -875,13 +1214,13 @@ public PlayerAdvancements getPlayerAdvancements(ServerPlayer player) { UUID uuid = player.getUUID(); @@ -924,7 +974,7 @@ } advancementdataplayer.setPlayer(player); -@@ -932,15 +1253,28 @@ +@@ -932,15 +1271,28 @@ } public void reloadResources() { diff --git a/paper-server/patches/sources/net/minecraft/world/BossEvent.java.patch b/paper-server/patches/sources/net/minecraft/world/BossEvent.java.patch new file mode 100644 index 0000000000..3210ddc320 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/BossEvent.java.patch @@ -0,0 +1,86 @@ +--- a/net/minecraft/world/BossEvent.java ++++ b/net/minecraft/world/BossEvent.java +@@ -13,6 +13,7 @@ + protected boolean darkenScreen; + protected boolean playBossMusic; + protected boolean createWorldFog; ++ public net.kyori.adventure.bossbar.BossBar adventure; // Paper + + public BossEvent(UUID uuid, Component name, BossEvent.BossBarColor color, BossEvent.BossBarOverlay style) { + this.id = uuid; +@@ -27,61 +28,75 @@ + } + + public Component getName() { ++ if (this.adventure != null) return io.papermc.paper.adventure.PaperAdventure.asVanilla(this.adventure.name()); // Paper + return this.name; + } + + public void setName(Component name) { ++ if (this.adventure != null) this.adventure.name(io.papermc.paper.adventure.PaperAdventure.asAdventure(name)); // Paper + this.name = name; + } + + public float getProgress() { ++ if (this.adventure != null) return this.adventure.progress(); // Paper + return this.progress; + } + + public void setProgress(float percent) { ++ if (this.adventure != null) this.adventure.progress(percent); // Paper + this.progress = percent; + } + + public BossEvent.BossBarColor getColor() { ++ if (this.adventure != null) return io.papermc.paper.adventure.PaperAdventure.asVanilla(this.adventure.color()); // Paper + return this.color; + } + + public void setColor(BossEvent.BossBarColor color) { ++ if (this.adventure != null) this.adventure.color(io.papermc.paper.adventure.PaperAdventure.asAdventure(color)); // Paper + this.color = color; + } + + public BossEvent.BossBarOverlay getOverlay() { ++ if (this.adventure != null) return io.papermc.paper.adventure.PaperAdventure.asVanilla(this.adventure.overlay()); // Paper + return this.overlay; + } + + public void setOverlay(BossEvent.BossBarOverlay style) { ++ if (this.adventure != null) this.adventure.overlay(io.papermc.paper.adventure.PaperAdventure.asAdventure(style)); // Paper + this.overlay = style; + } + + public boolean shouldDarkenScreen() { ++ if (this.adventure != null) return this.adventure.hasFlag(net.kyori.adventure.bossbar.BossBar.Flag.DARKEN_SCREEN); // Paper + return this.darkenScreen; + } + + public BossEvent setDarkenScreen(boolean darkenSky) { ++ if (this.adventure != null) io.papermc.paper.adventure.PaperAdventure.setFlag(this.adventure, net.kyori.adventure.bossbar.BossBar.Flag.DARKEN_SCREEN, darkenSky); // Paper + this.darkenScreen = darkenSky; + return this; + } + + public boolean shouldPlayBossMusic() { ++ if (this.adventure != null) return this.adventure.hasFlag(net.kyori.adventure.bossbar.BossBar.Flag.PLAY_BOSS_MUSIC); // Paper + return this.playBossMusic; + } + + public BossEvent setPlayBossMusic(boolean dragonMusic) { ++ if (this.adventure != null) io.papermc.paper.adventure.PaperAdventure.setFlag(this.adventure, net.kyori.adventure.bossbar.BossBar.Flag.PLAY_BOSS_MUSIC, dragonMusic); // Paper + this.playBossMusic = dragonMusic; + return this; + } + + public BossEvent setCreateWorldFog(boolean thickenFog) { ++ if (this.adventure != null) io.papermc.paper.adventure.PaperAdventure.setFlag(this.adventure, net.kyori.adventure.bossbar.BossBar.Flag.CREATE_WORLD_FOG, thickenFog); // Paper + this.createWorldFog = thickenFog; + return this; + } + + public boolean shouldCreateWorldFog() { ++ if (this.adventure != null) return this.adventure.hasFlag(net.kyori.adventure.bossbar.BossBar.Flag.CREATE_WORLD_FOG); // Paper + return this.createWorldFog; + } + diff --git a/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch b/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch index 6c5f780b27..30333ebd21 100644 --- a/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/item/ItemStack.java.patch @@ -89,7 +89,7 @@ return instance.group(Item.CODEC.fieldOf("id").forGetter(ItemStack::getItemHolder), DataComponentPatch.CODEC.optionalFieldOf("components", DataComponentPatch.EMPTY).forGetter((itemstack) -> { return itemstack.components.asPatch(); })).apply(instance, (holder, datacomponentpatch) -> { -@@ -132,19 +161,29 @@ +@@ -132,20 +161,38 @@ if (i <= 0) { return ItemStack.EMPTY; } else { @@ -120,10 +120,19 @@ + CraftItemStack.setItemMeta(itemstack, CraftItemStack.getItemMeta(itemstack)); + // Spigot end + ITEM_STREAM_CODEC.encode(registryfriendlybytebuf, itemstack.getItemHolder()); // CraftBukkit - decompile error ++ // Paper start - adventure; conditionally render translatable components ++ boolean prev = net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.get(); ++ try { ++ net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(true); DataComponentPatch.STREAM_CODEC.encode(registryfriendlybytebuf, itemstack.components.asPatch()); ++ } finally { ++ net.minecraft.network.chat.ComponentSerialization.DONT_RENDER_TRANSLATABLES.set(prev); ++ } ++ // Paper end - adventure; conditionally render translatable components } } -@@ -187,7 +226,7 @@ + }; +@@ -187,7 +234,7 @@ return dataresult.isError() ? dataresult.map((unit) -> { return stack; @@ -132,7 +141,7 @@ int i = stack.getCount(); return "Item stack with stack size of " + i + " was larger than maximum: " + stack.getMaxStackSize(); -@@ -294,8 +333,9 @@ +@@ -294,8 +341,9 @@ j = itemstack.getMaxStackSize(); } while (i <= j); @@ -143,7 +152,7 @@ }); } } -@@ -370,32 +410,190 @@ +@@ -370,32 +418,190 @@ } public InteractionResult useOn(UseOnContext context) { @@ -339,7 +348,7 @@ ItemStack itemstack = this.copy(); boolean flag = this.getUseDuration(user) <= 0; InteractionResult enuminteractionresult = this.getItem().use(world, user, hand); -@@ -492,7 +690,22 @@ +@@ -492,7 +698,22 @@ public void hurtAndBreak(int amount, ServerLevel world, @Nullable ServerPlayer player, Consumer breakCallback) { int j = this.processDurabilityChange(amount, world, player); @@ -362,7 +371,7 @@ if (j != 0) { this.applyDamage(this.getDamageValue() + j, player, breakCallback); } -@@ -511,6 +724,11 @@ +@@ -511,6 +732,11 @@ this.setDamageValue(damage); if (this.isBroken()) { Item item = this.getItem(); @@ -374,7 +383,7 @@ this.shrink(1); breakCallback.accept(item); -@@ -518,7 +736,7 @@ +@@ -518,7 +744,7 @@ } @@ -383,7 +392,7 @@ if (player instanceof ServerPlayer entityplayer) { int j = this.processDurabilityChange(amount, entityplayer.serverLevel(), entityplayer); -@@ -580,11 +798,11 @@ +@@ -580,11 +806,11 @@ return this.getItem().getBarColor(this); } @@ -397,7 +406,7 @@ return this.getItem().overrideOtherStackedOnMe(this, stack, slot, clickType, player, cursorStackReference); } -@@ -592,8 +810,8 @@ +@@ -592,8 +818,8 @@ Item item = this.getItem(); if (item.hurtEnemy(this, target, user)) { @@ -408,7 +417,7 @@ entityhuman.awardStat(Stats.ITEM_USED.get(item)); } -@@ -608,7 +826,7 @@ +@@ -608,7 +834,7 @@ this.getItem().postHurtEnemy(this, target, user); } @@ -417,7 +426,7 @@ Item item = this.getItem(); if (item.mineBlock(this, world, state, pos, miner)) { -@@ -617,11 +835,11 @@ +@@ -617,11 +843,11 @@ } @@ -431,7 +440,7 @@ return this.getItem().interactLivingEntity(this, user, entity, hand); } -@@ -736,7 +954,7 @@ +@@ -736,7 +962,7 @@ } @@ -440,7 +449,7 @@ player.awardStat(Stats.ITEM_CRAFTED.get(this.getItem()), amount); this.getItem().onCraftedBy(this, world, player); } -@@ -768,7 +986,13 @@ +@@ -768,7 +994,13 @@ public boolean useOnRelease() { return this.getItem().useOnRelease(this); @@ -454,12 +463,10 @@ @Nullable public T set(DataComponentType type, @Nullable T value) { -@@ -804,7 +1028,26 @@ - } else { - this.getItem().verifyComponentsAfterLoad(this); +@@ -806,6 +1038,25 @@ } -+ } -+ + } + + // Paper start - (this is just a good no conflict location) + public org.bukkit.inventory.ItemStack asBukkitMirror() { + return CraftItemStack.asCraftMirror(this); @@ -476,12 +483,13 @@ + bukkitStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(this); + } + return bukkitStack; - } ++ } + // Paper end - ++ public void applyComponents(DataComponentPatch changes) { this.components.applyPatch(changes); -@@ -858,7 +1101,7 @@ + this.getItem().verifyComponentsAfterLoad(this); +@@ -858,7 +1109,7 @@ } private void addToTooltip(DataComponentType componentType, Item.TooltipContext context, Consumer textConsumer, TooltipFlag type) { @@ -490,7 +498,7 @@ if (t0 != null) { t0.addToTooltip(context, textConsumer, type); -@@ -866,7 +1109,7 @@ +@@ -866,7 +1117,7 @@ } @@ -499,7 +507,7 @@ boolean flag = this.getItem().shouldPrintOpWarning(this, player); if (!type.isCreative() && this.has(DataComponents.HIDE_TOOLTIP)) { -@@ -941,7 +1184,7 @@ +@@ -941,7 +1192,7 @@ } } @@ -508,7 +516,7 @@ ItemAttributeModifiers itemattributemodifiers = (ItemAttributeModifiers) this.getOrDefault(DataComponents.ATTRIBUTE_MODIFIERS, ItemAttributeModifiers.EMPTY); if (itemattributemodifiers.showInTooltip()) { -@@ -966,7 +1209,7 @@ +@@ -966,7 +1217,7 @@ } } @@ -517,7 +525,7 @@ double d0 = modifier.amount(); boolean flag = false; -@@ -1091,6 +1334,14 @@ +@@ -1091,6 +1342,14 @@ EnchantmentHelper.forEachModifier(this, slot, attributeModifierConsumer); } @@ -532,7 +540,7 @@ public Component getDisplayName() { MutableComponent ichatmutablecomponent = Component.empty().append(this.getHoverName()); -@@ -1153,7 +1404,7 @@ +@@ -1153,7 +1412,7 @@ } public void consume(int amount, @Nullable LivingEntity entity) { diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch index 25868e4bc2..1112964221 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch @@ -109,22 +109,22 @@ - return text; + // CraftBukkit start + Player player = ((ServerPlayer) entityhuman).getBukkitEntity(); -+ String[] lines = new String[4]; ++ List lines = new java.util.ArrayList<>(); // Paper - adventure + + for (int i = 0; i < list.size(); ++i) { -+ lines[i] = CraftChatMessage.fromComponent(signtext.getMessage(i, entityhuman.isTextFilteringEnabled())); ++ lines.add(io.papermc.paper.adventure.PaperAdventure.asAdventure(signtext.getMessage(i, entityhuman.isTextFilteringEnabled()))); // Paper - Adventure + } + -+ SignChangeEvent event = new SignChangeEvent(CraftBlock.at(this.level, this.worldPosition), player, lines.clone(), (front) ? Side.FRONT : Side.BACK); ++ SignChangeEvent event = new SignChangeEvent(CraftBlock.at(this.level, this.worldPosition), player, new java.util.ArrayList<>(lines), (front) ? Side.FRONT : Side.BACK); // Paper - Adventure + entityhuman.level().getCraftServer().getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return originalText; + } + -+ Component[] components = org.bukkit.craftbukkit.block.CraftSign.sanitizeLines(event.getLines()); ++ Component[] components = org.bukkit.craftbukkit.block.CraftSign.sanitizeLines(event.lines()); // Paper - Adventure + for (int i = 0; i < components.length; i++) { -+ if (!Objects.equals(lines[i], event.getLine(i))) { ++ if (!Objects.equals(lines.get(i), event.line(i))) { // Paper - Adventure + signtext = signtext.setMessage(i, components[i]); + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch index 6c740e3304..5374847788 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java.patch @@ -1,10 +1,11 @@ --- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -47,6 +47,16 @@ +@@ -47,6 +47,17 @@ import net.minecraft.world.level.saveddata.SavedData; import org.slf4j.Logger; +// CraftBukkit start ++import io.papermc.paper.adventure.PaperAdventure; // Paper +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.CraftServer; @@ -17,7 +18,7 @@ public class MapItemSavedData extends SavedData { private static final Logger LOGGER = LogUtils.getLogger(); -@@ -70,6 +80,13 @@ +@@ -70,6 +81,13 @@ private final Map frameMarkers = Maps.newHashMap(); private int trackedDecorationCount; @@ -31,7 +32,7 @@ public static SavedData.Factory factory() { return new SavedData.Factory<>(() -> { throw new IllegalStateException("Should never create an empty map saved data"); -@@ -84,6 +101,10 @@ +@@ -84,6 +102,10 @@ this.trackingPosition = showDecorations; this.unlimitedTracking = unlimitedTracking; this.locked = locked; @@ -42,7 +43,7 @@ } public static MapItemSavedData createFresh(double centerX, double centerZ, byte scale, boolean showDecorations, boolean unlimitedTracking, ResourceKey dimension) { -@@ -101,12 +122,30 @@ +@@ -101,12 +123,30 @@ } public static MapItemSavedData load(CompoundTag nbt, HolderLookup.Provider registries) { @@ -76,7 +77,7 @@ }); int i = nbt.getInt("xCenter"); int j = nbt.getInt("zCenter"); -@@ -131,7 +170,8 @@ +@@ -131,7 +171,8 @@ MapBanner mapiconbanner = (MapBanner) iterator.next(); worldmap.bannerMarkers.put(mapiconbanner.getId(), mapiconbanner); @@ -86,7 +87,7 @@ } ListTag nbttaglist = nbt.getList("frames", 10); -@@ -150,13 +190,32 @@ +@@ -150,13 +191,32 @@ @Override public CompoundTag save(CompoundTag nbt, HolderLookup.Provider registries) { @@ -120,7 +121,7 @@ nbt.putInt("xCenter", this.centerX); nbt.putInt("zCenter", this.centerZ); nbt.putByte("scale", this.scale); -@@ -443,7 +502,7 @@ +@@ -443,7 +503,7 @@ if (!this.isTrackedCountOverLimit(256)) { this.bannerMarkers.put(mapiconbanner.getId(), mapiconbanner); @@ -129,7 +130,7 @@ return true; } } -@@ -554,7 +613,7 @@ +@@ -554,7 +614,7 @@ this.player = entityhuman; } @@ -138,7 +139,7 @@ int i = this.minDirtyX; int j = this.minDirtyY; int k = this.maxDirtyX + 1 - this.minDirtyX; -@@ -563,7 +622,7 @@ +@@ -563,7 +623,7 @@ for (int i1 = 0; i1 < k; ++i1) { for (int j1 = 0; j1 < l; ++j1) { @@ -147,7 +148,7 @@ } } -@@ -573,19 +632,29 @@ +@@ -573,19 +633,29 @@ @Nullable Packet nextUpdatePacket(MapId mapId) { MapItemSavedData.MapPatch worldmap_c; @@ -172,7 +173,7 @@ + + for (org.bukkit.map.MapCursor cursor : render.cursors) { + if (cursor.isVisible()) { -+ icons.add(new MapDecoration(CraftMapCursor.CraftType.bukkitToMinecraftHolder(cursor.getType()), cursor.getX(), cursor.getY(), cursor.getDirection(), CraftChatMessage.fromStringOrOptional(cursor.getCaption()))); ++ icons.add(new MapDecoration(CraftMapCursor.CraftType.bukkitToMinecraftHolder(cursor.getType()), cursor.getX(), cursor.getY(), cursor.getDirection(), Optional.ofNullable(PaperAdventure.asVanilla(cursor.caption())))); + } + } + collection = icons; diff --git a/paper-server/src/main/java/io/papermc/paper/adventure/AdventureCodecs.java b/paper-server/src/main/java/io/papermc/paper/adventure/AdventureCodecs.java new file mode 100644 index 0000000000..2c5702a42c --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/adventure/AdventureCodecs.java @@ -0,0 +1,450 @@ +package io.papermc.paper.adventure; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.datafixers.util.Either; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.BlockNBTComponent; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.EntityNBTComponent; +import net.kyori.adventure.text.KeybindComponent; +import net.kyori.adventure.text.NBTComponent; +import net.kyori.adventure.text.NBTComponentBuilder; +import net.kyori.adventure.text.ScoreComponent; +import net.kyori.adventure.text.SelectorComponent; +import net.kyori.adventure.text.StorageNBTComponent; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.TranslatableComponent; +import net.kyori.adventure.text.TranslationArgument; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.event.DataComponentValue; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import net.minecraft.commands.arguments.selector.SelectorPattern; +import net.minecraft.core.UUIDUtil; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.nbt.TagParser; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.network.chat.contents.KeybindContents; +import net.minecraft.network.chat.contents.ScoreContents; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.RegistryOps; +import net.minecraft.util.ExtraCodecs; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.DefaultQualifier; +import org.intellij.lang.annotations.Subst; + +import static com.mojang.serialization.Codec.recursive; +import static com.mojang.serialization.codecs.RecordCodecBuilder.mapCodec; +import static java.util.function.Function.identity; +import static net.kyori.adventure.text.Component.text; +import static net.kyori.adventure.text.TranslationArgument.bool; +import static net.kyori.adventure.text.TranslationArgument.component; +import static net.kyori.adventure.text.TranslationArgument.numeric; + +@DefaultQualifier(NonNull.class) +public final class AdventureCodecs { + + public static final Codec COMPONENT_CODEC = recursive("adventure Component", AdventureCodecs::createCodec); + public static final StreamCodec STREAM_COMPONENT_CODEC = ByteBufCodecs.fromCodecWithRegistriesTrusted(COMPONENT_CODEC); + + static final Codec TEXT_COLOR_CODEC = Codec.STRING.comapFlatMap(s -> { + if (s.startsWith("#")) { + @Nullable TextColor value = TextColor.fromHexString(s); + return value != null ? DataResult.success(value) : DataResult.error(() -> "Cannot convert " + s + " to adventure TextColor"); + } else { + final @Nullable NamedTextColor value = NamedTextColor.NAMES.value(s); + return value != null ? DataResult.success(value) : DataResult.error(() -> "Cannot convert " + s + " to adventure NamedTextColor"); + } + }, textColor -> { + if (textColor instanceof NamedTextColor named) { + return NamedTextColor.NAMES.keyOrThrow(named); + } else { + return textColor.asHexString(); + } + }); + + static final Codec KEY_CODEC = Codec.STRING.comapFlatMap(s -> { + return Key.parseable(s) ? DataResult.success(Key.key(s)) : DataResult.error(() -> "Cannot convert " + s + " to adventure Key"); + }, Key::asString); + + static final Codec CLICK_EVENT_ACTION_CODEC = Codec.STRING.comapFlatMap(s -> { + final ClickEvent.@Nullable Action value = ClickEvent.Action.NAMES.value(s); + return value != null ? DataResult.success(value) : DataResult.error(() -> "Cannot convert " + s + " to adventure ClickEvent$Action"); + }, ClickEvent.Action.NAMES::keyOrThrow); + static final Codec CLICK_EVENT_CODEC = RecordCodecBuilder.create((instance) -> { + return instance.group( + CLICK_EVENT_ACTION_CODEC.fieldOf("action").forGetter(ClickEvent::action), + Codec.STRING.fieldOf("value").forGetter(ClickEvent::value) + ).apply(instance, ClickEvent::clickEvent); + }); + + static Codec showEntityCodec(final Codec componentCodec) { + return RecordCodecBuilder.create((instance) -> { + return instance.group( + KEY_CODEC.fieldOf("type").forGetter(HoverEvent.ShowEntity::type), + UUIDUtil.LENIENT_CODEC.fieldOf("id").forGetter(HoverEvent.ShowEntity::id), + componentCodec.lenientOptionalFieldOf("name").forGetter(he -> Optional.ofNullable(he.name())) + ).apply(instance, (key, uuid, component) -> { + return HoverEvent.ShowEntity.showEntity(key, uuid, component.orElse(null)); + }); + }); + } + + static Codec showItemCodec(final Codec componentCodec) { + return net.minecraft.network.chat.HoverEvent.ItemStackInfo.CODEC.xmap(isi -> { + @Subst("key") final String typeKey = isi.item.unwrapKey().orElseThrow().location().toString(); + return HoverEvent.ShowItem.showItem(Key.key(typeKey), isi.count, PaperAdventure.asAdventure(isi.getItemStack().getComponentsPatch())); + }, si -> { + final Item itemType = BuiltInRegistries.ITEM.getValue(PaperAdventure.asVanilla(si.item())); + final Map dataComponentsMap = si.dataComponents(); + final ItemStack stack = new ItemStack(BuiltInRegistries.ITEM.wrapAsHolder(itemType), si.count(), PaperAdventure.asVanilla(dataComponentsMap)); + return new net.minecraft.network.chat.HoverEvent.ItemStackInfo(stack); + }); + } + + static final HoverEventType SHOW_ENTITY_HOVER_EVENT_TYPE = new HoverEventType<>(AdventureCodecs::showEntityCodec, HoverEvent.Action.SHOW_ENTITY, "show_entity", AdventureCodecs::legacyDeserializeEntity); + static final HoverEventType SHOW_ITEM_HOVER_EVENT_TYPE = new HoverEventType<>(AdventureCodecs::showItemCodec, HoverEvent.Action.SHOW_ITEM, "show_item", AdventureCodecs::legacyDeserializeItem); + static final HoverEventType SHOW_TEXT_HOVER_EVENT_TYPE = new HoverEventType<>(identity(), HoverEvent.Action.SHOW_TEXT, "show_text", (component, registryOps, codec) -> DataResult.success(component)); + static final Codec> HOVER_EVENT_TYPE_CODEC = StringRepresentable.fromValues(() -> new HoverEventType[]{ SHOW_ENTITY_HOVER_EVENT_TYPE, SHOW_ITEM_HOVER_EVENT_TYPE, SHOW_TEXT_HOVER_EVENT_TYPE }); + + static DataResult legacyDeserializeEntity(final Component component, final @Nullable RegistryOps ops, final Codec componentCodec) { + try { + final CompoundTag tag = TagParser.parseTag(PlainTextComponentSerializer.plainText().serialize(component)); + final DynamicOps dynamicOps = ops != null ? ops.withParent(JsonOps.INSTANCE) : JsonOps.INSTANCE; + final DataResult entityNameResult = componentCodec.parse(dynamicOps, JsonParser.parseString(tag.getString("name"))); + @Subst("key") final String keyString = tag.getString("type"); + final UUID entityUUID = UUID.fromString(tag.getString("id")); + return entityNameResult.map(name -> HoverEvent.ShowEntity.showEntity(Key.key(keyString), entityUUID, name)); + } catch (final Exception ex) { + return DataResult.error(() -> "Failed to parse tooltip: " + ex.getMessage()); + } + } + + static DataResult legacyDeserializeItem(final Component component, final @Nullable RegistryOps ops, final Codec componentCodec) { + try { + final CompoundTag tag = TagParser.parseTag(PlainTextComponentSerializer.plainText().serialize(component)); + final DynamicOps dynamicOps = ops != null ? ops.withParent(NbtOps.INSTANCE) : NbtOps.INSTANCE; + final DataResult stackResult = ItemStack.CODEC.parse(dynamicOps, tag); + return stackResult.map(stack -> { + @Subst("key:value") final String location = stack.getItemHolder().unwrapKey().orElseThrow().location().toString(); + return HoverEvent.ShowItem.showItem(Key.key(location), stack.getCount(), PaperAdventure.asAdventure(stack.getComponentsPatch())); + }); + } catch (final CommandSyntaxException ex) { + return DataResult.error(() -> "Failed to parse item tag: " + ex.getMessage()); + } + } + + @FunctionalInterface + interface LegacyDeserializer { + DataResult apply(Component component, @Nullable RegistryOps ops, Codec componentCodec); + } + + record HoverEventType(Function, MapCodec>> codec, String id, Function, MapCodec>> legacyCodec) implements StringRepresentable { + HoverEventType(final Function, Codec> contentCodec, final HoverEvent.Action action, final String id, final LegacyDeserializer legacyDeserializer) { + this(cc -> contentCodec.apply(cc).xmap(v -> HoverEvent.hoverEvent(action, v), HoverEvent::value).fieldOf("contents"), + id, + codec -> (new Codec>() { + public DataResult, D>> decode(final DynamicOps dynamicOps, final D object) { + return codec.decode(dynamicOps, object).flatMap(pair -> { + final DataResult dataResult; + if (dynamicOps instanceof final RegistryOps registryOps) { + dataResult = legacyDeserializer.apply(pair.getFirst(), registryOps, codec); + } else { + dataResult = legacyDeserializer.apply(pair.getFirst(), null, codec); + } + + return dataResult.map(value -> Pair.of(HoverEvent.hoverEvent(action, value), pair.getSecond())); + }); + } + + public DataResult encode(final HoverEvent hoverEvent, final DynamicOps dynamicOps, final D object) { + return DataResult.error(() -> "Can't encode in legacy format"); + } + }).fieldOf("value") + ); + } + @Override + public String getSerializedName() { + return this.id; + } + } + + private static final Function, HoverEventType> GET_HOVER_EVENT_TYPE = he -> { + if (he.action() == HoverEvent.Action.SHOW_ENTITY) { + return SHOW_ENTITY_HOVER_EVENT_TYPE; + } else if (he.action() == HoverEvent.Action.SHOW_ITEM) { + return SHOW_ITEM_HOVER_EVENT_TYPE; + } else if (he.action() == HoverEvent.Action.SHOW_TEXT) { + return SHOW_TEXT_HOVER_EVENT_TYPE; + } else { + throw new IllegalStateException(); + } + }; + static final Codec> HOVER_EVENT_CODEC = Codec.withAlternative( + HOVER_EVENT_TYPE_CODEC.>dispatchMap("action", GET_HOVER_EVENT_TYPE, het -> het.codec.apply(COMPONENT_CODEC)).codec(), + HOVER_EVENT_TYPE_CODEC.>dispatchMap("action", GET_HOVER_EVENT_TYPE, het -> het.legacyCodec.apply(COMPONENT_CODEC)).codec() + ); + + public static final MapCodec