Created
March 5, 2026 11:01
-
-
Save Ensamisten/524393767cafa20f5683cf478d9155c2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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