Skip to content

Instantly share code, notes, and snippets.

@Ensamisten
Created March 5, 2026 11:01
Show Gist options
  • Select an option

  • Save Ensamisten/524393767cafa20f5683cf478d9155c2 to your computer and use it in GitHub Desktop.

Select an option

Save Ensamisten/524393767cafa20f5683cf478d9155c2 to your computer and use it in GitHub Desktop.
package io.github.ensamisten.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.Clipboard;
import net.minecraft.client.util.Window;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.NbtComponent;
import net.minecraft.component.type.WritableBookContentComponent;
import net.minecraft.component.type.WrittenBookContentComponent;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.RawFilteredPair;
import net.minecraft.text.Text;
import org.lwjgl.glfw.GLFWErrorCallback;
import java.util.ArrayList;
import java.util.List;
public class FabrientBookCommand {
private static final Clipboard clipboardManager = new Clipboard();
static Window window = MinecraftClient.getInstance().getWindow();
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(
CommandManager.literal("book")
.then(CommandManager.literal("write")
.then(CommandManager.literal("nbt")
.executes(FabrientBookCommand::writeNbt))
.then(CommandManager.literal("text")
.executes(FabrientBookCommand::writeText)))
.then(CommandManager.literal("read")
.then(CommandManager.literal("nbt")
.executes(FabrientBookCommand::readNbt))
.then(CommandManager.literal("text")
.executes(FabrientBookCommand::readText))));
}
private static int writeText(CommandContext<ServerCommandSource> context) {
PlayerEntity player = context.getSource().getPlayer();
ItemStack heldItem = player.getMainHandStack();
if (heldItem.getItem() == Items.WRITABLE_BOOK) {
String clipboardText = clipboardManager.get(window, GLFWErrorCallback.createPrint(System.err));
if (clipboardText.isEmpty()) {
context.getSource().sendError(Text.literal("Clipboard is empty!"));
return 0;
}
List<RawFilteredPair<String>> pages = new ArrayList<>();
StringBuilder currentPage = new StringBuilder();
for (int i = 0; i < clipboardText.length(); i++) {
currentPage.append(clipboardText.charAt(i));
if (currentPage.length() >= 256 || i == clipboardText.length() - 1) {
// RawFilteredPair.of(raw, filtered) — use same string for both
pages.add(RawFilteredPair.of(currentPage.toString()));
currentPage = new StringBuilder();
}
}
heldItem.set(DataComponentTypes.WRITABLE_BOOK_CONTENT, new WritableBookContentComponent(pages));
context.getSource().sendMessage(Text.literal("Clipboard contents written to the book!"));
return 1;
} else {
context.getSource().sendError(Text.literal("You need to hold a writable book in your hand!"));
return 0;
}
}
private static int writeNbt(CommandContext<ServerCommandSource> context) {
PlayerEntity player = context.getSource().getPlayer();
ItemStack heldItem = player.getMainHandStack();
if (heldItem.getItem() == Items.WRITABLE_BOOK) {
String clipboardText = clipboardManager.get(window, GLFWErrorCallback.createPrint(System.err));
if (clipboardText.isEmpty()) {
context.getSource().sendError(Text.literal("Clipboard is empty!"));
return 0;
}
// Use CUSTOM_DATA component to store raw NBT
NbtCompound nbt = new NbtCompound();
nbt.putString("raw_data", clipboardText);
heldItem.set(DataComponentTypes.CUSTOM_DATA, NbtComponent.of(nbt));
context.getSource().sendMessage(Text.literal("Clipboard contents written to the book!"));
return 1;
} else {
context.getSource().sendError(Text.literal("You need to hold a writable book in your hand!"));
return 0;
}
}
private static int readNbt(CommandContext<ServerCommandSource> context) {
PlayerEntity player = context.getSource().getPlayer();
ItemStack heldItem = player.getMainHandStack();
if (heldItem.getItem() == Items.WRITABLE_BOOK || heldItem.getItem() == Items.WRITTEN_BOOK) {
NbtComponent customData = heldItem.get(DataComponentTypes.CUSTOM_DATA);
if (customData != null) {
NbtCompound nbt = customData.copyNbt();
if (nbt.contains("raw_data")) { // ✅ call contains() on NbtCompound, not NbtComponent
String rawData = nbt.getString("raw_data").orElse(""); // ✅ unwrap Optional<String>
if (rawData.isEmpty()) {
context.getSource().sendError(Text.literal("The book does not contain raw data!"));
return 0;
}
clipboardManager.set(window, rawData);
context.getSource().sendMessage(Text.literal("Clipboard contents read from the book!"));
return 1;
}
}
context.getSource().sendError(Text.literal("The book does not contain raw data!"));
return 0;
} else {
context.getSource().sendError(Text.literal("You need to hold a written book in your hand!"));
return 0;
}
}
private static int readText(CommandContext<ServerCommandSource> context) {
PlayerEntity player = context.getSource().getPlayer();
ItemStack heldItem = player.getMainHandStack();
if (heldItem.getItem() == Items.WRITABLE_BOOK) {
WritableBookContentComponent content = heldItem.get(DataComponentTypes.WRITABLE_BOOK_CONTENT);
if (content != null && !content.pages().isEmpty()) {
StringBuilder textBuilder = new StringBuilder();
for (RawFilteredPair<String> page : content.pages()) {
textBuilder.append(page.raw()).append("\n");
}
clipboardManager.set(window, textBuilder.toString().trim());
context.getSource().sendMessage(Text.literal("Book text copied to clipboard!"));
return 1;
} else {
context.getSource().sendError(Text.literal("The book is empty!"));
return 0;
}
} else if (heldItem.getItem() == Items.WRITTEN_BOOK) {
WrittenBookContentComponent content = heldItem.get(DataComponentTypes.WRITTEN_BOOK_CONTENT);
if (content != null && !content.pages().isEmpty()) {
StringBuilder textBuilder = new StringBuilder();
for (RawFilteredPair<Text> page : content.pages()) {
textBuilder.append(page.raw().getString()).append("\n");
}
clipboardManager.set(window, textBuilder.toString().trim());
context.getSource().sendMessage(Text.literal("Book text copied to clipboard!"));
return 1;
} else {
context.getSource().sendError(Text.literal("The book is empty!"));
return 0;
}
} else {
context.getSource().sendError(Text.literal("You need to hold a written book in your hand!"));
return 0;
}
}
}
package io.github.densamisten.command;
import com.mojang.blaze3d.platform.ClipboardManager;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.*;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.item.component.WritableBookContent;
import net.minecraft.world.item.component.WrittenBookContent;
import net.minecraft.world.item.component.FilteredText;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import java.util.ArrayList;
import java.util.List;
public class BookCommand {
private static final ClipboardManager clipboardManager = new ClipboardManager();
public BookCommand(CommandDispatcher<CommandSourceStack> dispatcher) {
dispatcher.register(
Commands.literal("book")
.then(Commands.literal("write")
.then(Commands.literal("nbt")
.executes(BookCommand::writeNbt))
.then(Commands.literal("text")
.executes(BookCommand::writeText)))
.then(Commands.literal("read")
.then(Commands.literal("nbt")
.executes(BookCommand::readNbt))
.then(Commands.literal("text")
.executes(BookCommand::readText)))
.then(Commands.literal("copy")
.then(Commands.argument("target", EntityArgument.player())
.executes(context -> copyBook(context, EntityArgument.getPlayer(context, "target"))))));
}
private static int writeText(CommandContext<CommandSourceStack> context) {
Player player = context.getSource().getPlayer();
ItemStack heldItem = player != null ? player.getMainHandItem() : null;
if (heldItem == null || heldItem.getItem() != Items.WRITABLE_BOOK) {
context.getSource().sendFailure(Component.literal("You need to hold a writable book in your hand!"));
return 0;
}
String clipboardText = clipboardManager.getClipboard(
GLFW.glfwGetCurrentContext(), GLFWErrorCallback.createPrint(System.err));
if (clipboardText.isEmpty()) {
context.getSource().sendFailure(Component.literal("Clipboard is empty!"));
return 0;
}
List<FilteredText<String>> pages = new ArrayList<>();
StringBuilder currentPage = new StringBuilder();
for (int i = 0; i < clipboardText.length(); i++) {
currentPage.append(clipboardText.charAt(i));
if (currentPage.length() >= 256 || i == clipboardText.length() - 1) {
// FilteredText.passThrough(raw) — unfiltered, same string for raw and filtered
pages.add(FilteredText.passThrough(currentPage.toString()));
currentPage = new StringBuilder();
}
}
// ✅ Set pages via the WritableBookContent component
heldItem.set(DataComponents.WRITABLE_BOOK_CONTENT, new WritableBookContent(pages));
context.getSource().sendSuccess(() -> Component.literal("Clipboard contents written to the book!"), false);
return 1;
}
private static int writeNbt(CommandContext<CommandSourceStack> context) {
Player player = context.getSource().getPlayer();
ItemStack heldItem = player != null ? player.getMainHandItem() : null;
if (heldItem == null || heldItem.getItem() != Items.WRITABLE_BOOK) {
context.getSource().sendFailure(Component.literal("You need to hold a writable book in your hand!"));
return 0;
}
String clipboardText = clipboardManager.getClipboard(
GLFW.glfwGetCurrentContext(), GLFWErrorCallback.createPrint(System.err));
if (clipboardText.isEmpty()) {
context.getSource().sendFailure(Component.literal("Clipboard is empty!"));
return 0;
}
// ✅ Store raw data using CUSTOM_DATA component
CompoundTag nbt = new CompoundTag();
nbt.putString("raw_data", clipboardText);
heldItem.set(DataComponents.CUSTOM_DATA, CustomData.of(nbt));
context.getSource().sendSuccess(() -> Component.literal("Clipboard contents written to the book!"), false);
return 1;
}
private static int readNbt(CommandContext<CommandSourceStack> context) {
Player player = context.getSource().getPlayer();
ItemStack heldItem = player != null ? player.getMainHandItem() : null;
if (heldItem == null || (heldItem.getItem() != Items.WRITABLE_BOOK && heldItem.getItem() != Items.WRITTEN_BOOK)) {
context.getSource().sendFailure(Component.literal("You need to hold a written book in your hand!"));
return 0;
}
// ✅ Read from CUSTOM_DATA component
CustomData customData = heldItem.get(DataComponents.CUSTOM_DATA);
if (customData != null) {
CompoundTag nbt = customData.copyTag();
if (nbt.contains("raw_data")) {
// ✅ getString() returns Optional<String> in 1.21.1+
String rawData = nbt.getString("raw_data").orElse("");
if (!rawData.isEmpty()) {
clipboardManager.setClipboard(GLFW.glfwGetCurrentContext(), rawData);
context.getSource().sendSuccess(() -> Component.literal("Clipboard contents read from the book!"), false);
return 1;
}
}
}
context.getSource().sendFailure(Component.literal("The book does not contain raw data!"));
return 0;
}
private static int readText(CommandContext<CommandSourceStack> context) {
Player player = context.getSource().getPlayer();
ItemStack heldItem = player != null ? player.getMainHandItem() : null;
if (heldItem == null) {
context.getSource().sendFailure(Component.literal("You need to hold a written book in your hand!"));
return 0;
}
// ✅ Writable book — read pages from WritableBookContent
if (heldItem.getItem() == Items.WRITABLE_BOOK) {
WritableBookContent content = heldItem.get(DataComponents.WRITABLE_BOOK_CONTENT);
if (content != null && !content.pages().isEmpty()) {
StringBuilder textBuilder = new StringBuilder();
for (FilteredText<String> page : content.pages()) {
textBuilder.append(page.raw()).append("\n");
}
clipboardManager.setClipboard(GLFW.glfwGetCurrentContext(), textBuilder.toString().trim());
context.getSource().sendSuccess(() -> Component.literal("Book text copied to clipboard!"), false);
return 1;
} else {
context.getSource().sendFailure(Component.literal("The book is empty!"));
return 0;
}
}
// ✅ Written book — read pages from WrittenBookContent
if (heldItem.getItem() == Items.WRITTEN_BOOK) {
WrittenBookContent content = heldItem.get(DataComponents.WRITTEN_BOOK_CONTENT);
if (content != null && !content.pages().isEmpty()) {
StringBuilder textBuilder = new StringBuilder();
for (FilteredText<Component> page : content.pages()) {
textBuilder.append(page.raw().getString()).append("\n");
}
clipboardManager.setClipboard(GLFW.glfwGetCurrentContext(), textBuilder.toString().trim());
context.getSource().sendSuccess(() -> Component.literal("Book text copied to clipboard!"), false);
return 1;
} else {
context.getSource().sendFailure(Component.literal("The book is empty!"));
return 0;
}
}
context.getSource().sendFailure(Component.literal("You need to hold a written book in your hand!"));
return 0;
}
private static int copyBook(CommandContext<CommandSourceStack> context, ServerPlayer targetPlayer) throws CommandSyntaxException {
CommandSourceStack sourceStack = context.getSource();
ServerPlayer sourcePlayer = sourceStack.getPlayerOrException();
ItemStack heldItem = sourcePlayer.getMainHandItem();
if (!(heldItem.getItem() instanceof WritableBookItem || heldItem.getItem() instanceof WrittenBookItem)) {
sourceStack.sendFailure(Component.literal("You must be holding a written or writable book to copy."));
return 0;
}
ItemStack copiedBook = heldItem.copy();
copiedBook.setCount(1);
// ✅ Read title from WrittenBookContent component instead of CompoundTag
if (heldItem.getItem() instanceof WrittenBookItem) {
WrittenBookContent bookContent = heldItem.get(DataComponents.WRITTEN_BOOK_CONTENT);
if (bookContent != null) {
String title = bookContent.title().raw();
sourceStack.sendSuccess(() -> Component.literal(
"Copied book \"" + title + "\" to " + targetPlayer.getName().getString() + "'s inventory."), true);
targetPlayer.displayClientMessage(Component.literal(
"You received a copied book \"" + title + "\" from " + sourcePlayer.getName().getString() + "."), false);
}
}
Inventory targetInventory = targetPlayer.getInventory();
targetInventory.add(copiedBook);
return 1;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment