diff --git a/patches/server/Add-experimental-improved-give-command.patch b/patches/server/Add-experimental-improved-give-command.patch index f50207ee8c..9c65034ab1 100644 --- a/patches/server/Add-experimental-improved-give-command.patch +++ b/patches/server/Add-experimental-improved-give-command.patch @@ -23,6 +23,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } public static ItemArgument item(CommandBuildContext commandRegistryAccess) { +@@ -0,0 +0,0 @@ public class ItemArgument implements ArgumentType { + + public ItemInput parse(StringReader stringReader) throws CommandSyntaxException { + ItemParser.ItemResult itemResult = this.parser.parse(stringReader); +- return new ItemInput(itemResult.item(), itemResult.components()); ++ return new ItemInput(itemResult.item(), itemResult.components(), itemResult.patch()); // Paper - support component removals + } + + public static ItemInput getItem(CommandContext context, String name) { diff --git a/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java b/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/commands/arguments/item/ItemInput.java @@ -153,9 +162,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.suggestComponentAssignment(builder, true); + } + private CompletableFuture suggestComponentAssignment(SuggestionsBuilder builder, boolean suggestRemove) { -+ if (suggestRemove) builder.suggest("!", Component.literal("Remove a data component")); -+ // Paper end - support component removals String string = builder.getRemaining().toLowerCase(Locale.ROOT); ++ if (suggestRemove && string.isBlank()) builder.suggest("!", Component.literal("Remove a data component")); ++ // Paper end - support component removals SharedSuggestionProvider.filterResources(BuiltInRegistries.DATA_COMPONENT_TYPE.entrySet(), string, entry -> entry.getKey().location(), entry -> { DataComponentType dataComponentType = entry.getValue(); if (dataComponentType.codec() != null) { diff --git a/patches/server/Paper-dumpitem-command.patch b/patches/server/Paper-dumpitem-command.patch index dedec91967..c647f56605 100644 --- a/patches/server/Paper-dumpitem-command.patch +++ b/patches/server/Paper-dumpitem-command.patch @@ -27,24 +27,39 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + +import io.papermc.paper.adventure.PaperAdventure; +import io.papermc.paper.command.PaperSubcommand; -+import java.util.Objects; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.Map; ++import java.util.Optional; +import net.kyori.adventure.text.Component; -+import net.kyori.adventure.text.event.ClickEvent; ++import net.kyori.adventure.text.ComponentLike; ++import net.kyori.adventure.text.JoinConfiguration; ++import net.kyori.adventure.text.TextComponent; ++import net.minecraft.core.Registry; ++import net.minecraft.core.RegistryAccess; ++import net.minecraft.core.component.DataComponentPatch; ++import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.registries.Registries; -+import net.minecraft.nbt.CompoundTag; ++import net.minecraft.nbt.NbtOps; ++import net.minecraft.nbt.NbtUtils; ++import net.minecraft.nbt.Tag; ++import net.minecraft.resources.RegistryOps; +import net.minecraft.world.item.ItemStack; -+import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; -+import org.bukkit.craftbukkit.CraftWorld; -+import org.bukkit.craftbukkit.entity.CraftPlayer; ++import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.checkerframework.checker.nullness.qual.NonNull; -+import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.framework.qual.DefaultQualifier; + ++import static net.kyori.adventure.text.Component.join; +import static net.kyori.adventure.text.Component.text; ++import static net.kyori.adventure.text.Component.textOfChildren; ++import static net.kyori.adventure.text.event.ClickEvent.copyToClipboard; ++import static net.kyori.adventure.text.format.NamedTextColor.AQUA; +import static net.kyori.adventure.text.format.NamedTextColor.GRAY; ++import static net.kyori.adventure.text.format.NamedTextColor.RED; ++import static net.kyori.adventure.text.format.NamedTextColor.WHITE; +import static net.kyori.adventure.text.format.NamedTextColor.YELLOW; +import static net.kyori.adventure.text.format.TextDecoration.ITALIC; + @@ -57,31 +72,48 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + private void doDumpItem(final CommandSender sender) { -+ if (true) throw new UnsupportedOperationException("FIXME"); // TODO -+ /* -+ if (!(sender instanceof Player)) { ++ if (!(sender instanceof final Player player)) { + sender.sendMessage("Only players can use this command"); + return; + } -+ final ItemStack itemStack = CraftItemStack.asNMSCopy(((CraftPlayer) sender).getItemInHand()); -+ final @Nullable CompoundTag tag = itemStack.getTag(); -+ final @Nullable Component nbtComponent = tag == null ? null : PaperAdventure.asAdventure(net.minecraft.nbt.NbtUtils.toPrettyComponent(tag)); -+ final String itemId = Objects.requireNonNull(((CraftWorld) ((CraftPlayer) sender).getWorld()).getHandle().registryAccess() -+ .registryOrThrow(Registries.ITEM).getKey(itemStack.getItem())).toString(); -+ final Component message = text() -+ .append(text(itemId, YELLOW)) -+ .apply(b -> { -+ if (nbtComponent != null) { -+ b.append(nbtComponent); ++ final ItemStack itemStack = CraftItemStack.asNMSCopy(player.getInventory().getItemInMainHand()); ++ final TextComponent.Builder visualOutput = Component.text(); ++ final StringBuilder itemCommandBuilder = new StringBuilder(); ++ final String itemName = itemStack.getItemHolder().unwrapKey().orElseThrow().location().toString(); ++ itemCommandBuilder.append(itemName); ++ visualOutput.append(text(itemName, YELLOW)); // item type ++ final DataComponentPatch patch = itemStack.getComponentsPatch(); ++ ++ final RegistryAccess.Frozen access = ((CraftServer) sender.getServer()).getServer().registryAccess(); ++ final RegistryOps ops = access.createSerializationContext(NbtOps.INSTANCE); ++ final Registry> registry = access.registryOrThrow(Registries.DATA_COMPONENT_TYPE); ++ if (!patch.isEmpty()) { ++ visualOutput.append(text("[", WHITE)); ++ itemCommandBuilder.append("["); ++ final List componentComponents = new ArrayList<>(); ++ final List commandComponents = new ArrayList<>(); ++ for (final Map.Entry, Optional> entry : patch.entrySet()) { ++ final String path = registry.getResourceKey(entry.getKey()).orElseThrow().location().getPath(); ++ if (entry.getValue().isEmpty()) { ++ componentComponents.add(text().append(text('!', RED), text(path, AQUA))); ++ commandComponents.add("!" + path); ++ } else { ++ final Tag serialized = (Tag) ((DataComponentType) entry.getKey()).codecOrThrow().encodeStart(ops, entry.getValue().get()).getOrThrow(); ++ componentComponents.add(textOfChildren( ++ text(path, AQUA), ++ text("=", WHITE), ++ PaperAdventure.asAdventure(NbtUtils.toPrettyComponent(serialized)) ++ )); ++ commandComponents.add(path + "=" + serialized.getAsString()); + } -+ }) -+ .build(); -+ Bukkit.getConsoleSender().sendMessage(message); -+ sender.sendMessage(message); -+ sender.sendMessage(text().content(" Click to copy item to clipboard") -+ .color(GRAY) -+ .decorate(ITALIC) -+ .clickEvent(ClickEvent.copyToClipboard(tag == null ? itemId : (itemId + tag)))); -+ */ ++ ++ } ++ visualOutput ++ .append(join(JoinConfiguration.separator(text(",", WHITE)), componentComponents)) ++ .append(text("]", WHITE)); ++ itemCommandBuilder.append(String.join(",", commandComponents)).append("]"); ++ } ++ final Component hoverMsg = text("Click to copy item definition to clipboard for use with /pgive", GRAY, ITALIC); ++ player.sendMessage(visualOutput.build().compact().hoverEvent(hoverMsg).clickEvent(copyToClipboard(itemCommandBuilder.toString()))); + } +}