Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,24 @@
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.DataComponentMap;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.component.TypedDataComponent;
import net.minecraft.core.registries.Registries;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.SnbtPrinterTagVisitor;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.RegistryOps;
import net.minecraft.world.item.ItemStack;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftRegistry;
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 java.util.Objects.requireNonNull;
import static net.kyori.adventure.text.Component.join;
import static net.kyori.adventure.text.Component.text;
import static net.kyori.adventure.text.Component.textOfChildren;
Expand All @@ -56,71 +53,77 @@ public boolean execute(final CommandSender sender, final String subCommand, fina
return true;
}

@SuppressWarnings({"unchecked", "OptionalAssignedToNull", "rawtypes"})
@SuppressWarnings({"unchecked", "rawtypes"})
private void doDumpItem(final CommandSender sender, final boolean includeAllComponents) {
if (!(sender instanceof final Player player)) {
sender.sendMessage("Only players can use this command");
return;
}
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().identifier().toString();
itemCommandBuilder.append(itemName);
visualOutput.append(text(itemName, YELLOW)); // item type
final Set<DataComponentType<?>> referencedComponentTypes = Collections.newSetFromMap(new IdentityHashMap<>());
final DataComponentPatch patch = itemStack.getComponentsPatch();
referencedComponentTypes.addAll(patch.entrySet().stream().map(Map.Entry::getKey).toList());
final DataComponentMap prototype = itemStack.getItem().components();
final TextComponent.Builder output = Component.text();
final StringBuilder itemToCopy = new StringBuilder();
final ItemStack item = CraftItemStack.asNMSCopy(player.getInventory().getItemInMainHand());
final String itemName = item.getItemHolder().unwrapKey().orElseThrow().identifier().toString();
itemToCopy.append(itemName);
output.append(text(itemName, YELLOW)); // item type

final Set<DataComponentType<?>> remainingComponents = Collections.newSetFromMap(new IdentityHashMap<>());
final DataComponentPatch patch = item.getComponentsPatch();
remainingComponents.addAll(patch.entrySet().stream().map(Map.Entry::getKey).toList());
final DataComponentMap prototype = item.getPrototype();
if (includeAllComponents) {
referencedComponentTypes.addAll(prototype.keySet());
remainingComponents.addAll(prototype.keySet());
}
remainingComponents.removeIf(DataComponentType::isTransient);

final RegistryAccess.Frozen access = ((CraftServer) sender.getServer()).getServer().registryAccess();
final RegistryOps<Tag> ops = access.createSerializationContext(NbtOps.INSTANCE);
final Registry<DataComponentType<?>> registry = access.lookupOrThrow(Registries.DATA_COMPONENT_TYPE);
final List<ComponentLike> componentComponents = new ArrayList<>();
final List<String> commandComponents = new ArrayList<>();
for (final DataComponentType<?> type : referencedComponentTypes) {
final String path = registry.getResourceKey(type).orElseThrow().identifier().getPath();
final @Nullable Optional<?> patchedValue = patch.get(type);
final @Nullable TypedDataComponent<?> prototypeValue = prototype.getTyped(type);
if (patchedValue != null) {
final RegistryOps<Tag> ops = CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE);
final List<ComponentLike> writtenComponents = new ArrayList<>();
final List<String> componentsToCopy = new ArrayList<>();
for (final Map.Entry<DataComponentType<?>, Optional<?>> entry : patch.entrySet()) { // patch
final DataComponentType<?> type = entry.getKey();
if (remainingComponents.remove(type)) {
final String path = requireNonNull(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(type)).getPath();
final Optional<?> patchedValue = entry.getValue();
if (patchedValue.isEmpty()) {
componentComponents.add(text().append(text('!', RED), text(path, AQUA)));
commandComponents.add("!" + path);
writtenComponents.add(text().append(text('!', RED), text(path, AQUA)));
componentsToCopy.add("!" + path);
} else {
final Tag serialized = (Tag) ((DataComponentType) type).codecOrThrow().encodeStart(ops, patchedValue.get()).getOrThrow();
writeComponentValue(componentComponents::add, commandComponents::add, path, serialized);
writeComponentValue(writtenComponents::add, componentsToCopy::add, path, serialized);
}
} else if (includeAllComponents && prototypeValue != null) {
final Tag serialized = prototypeValue.encodeValue(ops).getOrThrow();
writeComponentValue(componentComponents::add, commandComponents::add, path, serialized);
}
}
if (!componentComponents.isEmpty()) {
visualOutput.append(

if (includeAllComponents) {
for (final DataComponentType<?> type : remainingComponents) { // prototype
final String path = requireNonNull(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(type)).getPath();
final Tag serialized = requireNonNull(prototype.getTyped(type)).encodeValue(ops).getOrThrow();
writeComponentValue(writtenComponents::add, componentsToCopy::add, path, serialized);
}
}

if (!writtenComponents.isEmpty()) {
output.append(
text("[", color(0x8910CE)),
join(JoinConfiguration.separator(text(",", GRAY)), componentComponents),
join(JoinConfiguration.separator(text(",", GRAY)), writtenComponents),
text("]", color(0x8910CE))
);
itemCommandBuilder
itemToCopy
.append("[")
.append(String.join(",", commandComponents))
.append(String.join(",", componentsToCopy))
.append("]");
}
player.sendMessage(visualOutput.build().compact());
player.sendMessage(output.build().compact());
final Component copyMsg = text("Click to copy item definition to clipboard for use with /give", GRAY, ITALIC);
sender.sendMessage(copyMsg.clickEvent(copyToClipboard(itemCommandBuilder.toString())));
sender.sendMessage(copyMsg.clickEvent(copyToClipboard(itemToCopy.toString())));
}

private static void writeComponentValue(final Consumer<Component> visualOutput, final Consumer<String> commandOutput, final String path, final Tag serialized) {
visualOutput.accept(textOfChildren(
private static void writeComponentValue(final Consumer<Component> output, final Consumer<String> copyOutput, final String path, final Tag serialized) {
output.accept(textOfChildren(
text(path, color(0xFF7FD7)),
text("=", WHITE),
PaperAdventure.asAdventure(NbtUtils.toPrettyComponent(serialized))
));
commandOutput.accept(path + "=" + new SnbtPrinterTagVisitor("", 0, new ArrayList<>()).visit(serialized));
copyOutput.accept(path + "=" + new SnbtPrinterTagVisitor("", 0, new ArrayList<>()).visit(serialized));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class TicksPerSecondCommand extends Command {
public TicksPerSecondCommand(String name) {
super(name);
this.description = "Gets the current ticks per second for the server";
this.usageMessage = "/tps";
this.usageMessage = "/tps [mem]";
this.setPermission("bukkit.command.tps");
}

Expand Down
Loading