Skip to content
Merged
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
7 changes: 4 additions & 3 deletions paper-api/src/main/java/org/bukkit/entity/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -3490,11 +3490,12 @@ default void setNoTickViewDistance(int viewDistance) {
public void updateCommands();

/**
* Open a {@link Material#WRITTEN_BOOK} for a Player
* Open an ItemStack with {@link io.papermc.paper.datacomponent.DataComponentTypes#WRITTEN_BOOK_CONTENT} for a Player
*
* @param book The book to open for this player
* @param book the item with written book content to open for this player
* @throws IllegalArgumentException if the ItemStack is null, empty or doesn't have a {@link io.papermc.paper.datacomponent.DataComponentTypes#WRITTEN_BOOK_CONTENT}
*/
public void openBook(ItemStack book);
void openBook(ItemStack book);

/**
* Open a Sign for editing by the Player.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import java.util.regex.Pattern;
import java.util.stream.StreamSupport;
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.inventory.Book;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.nbt.api.BinaryTagHolder;
import net.kyori.adventure.sound.Sound;
Expand All @@ -41,7 +40,6 @@
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.locale.Language;
import net.minecraft.nbt.CompoundTag;
Expand All @@ -55,13 +53,10 @@
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.network.Filterable;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.BossEvent;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.WrittenBookContent;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.command.VanillaCommandWrapper;
Expand Down Expand Up @@ -333,28 +328,6 @@ public static void setFlag(final BossBar bar, final BossBar.Flag flag, final boo
}
}

// Book

public static ItemStack asItemStack(final Book book, final Locale locale) {
final ItemStack item = new ItemStack(net.minecraft.world.item.Items.WRITTEN_BOOK, 1);
item.set(DataComponents.WRITTEN_BOOK_CONTENT, new WrittenBookContent(
Filterable.passThrough(validateField(asPlain(book.title(), locale), WrittenBookContent.TITLE_MAX_LENGTH, "title")),
asPlain(book.author(), locale),
0,
book.pages().stream().map(c -> Filterable.passThrough(PaperAdventure.asVanilla(c))).toList(), // TODO should we validate length?
false
));
return item;
}

private static String validateField(final String content, final int length, final String name) {
final int actual = content.length();
if (actual > length) {
throw new IllegalArgumentException("Field '" + name + "' has a maximum length of " + length + " but was passed '" + content + "', which was " + actual + " characters long.");
}
return content;
}

// Sounds

public static SoundSource asVanilla(final Sound.Source source) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import io.papermc.paper.FeatureHooks;
import io.papermc.paper.connection.PlayerGameConnection;
import io.papermc.paper.connection.PluginMessageBridgeImpl;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.datacomponent.item.WrittenBookContent;
import io.papermc.paper.dialog.Dialog;
import io.papermc.paper.dialog.PaperDialog;
import io.papermc.paper.entity.LookAnchor;
Expand Down Expand Up @@ -48,6 +50,7 @@
import java.util.stream.Collectors;
import net.kyori.adventure.dialog.DialogLike;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.inventory.Book;
import net.kyori.adventure.pointer.PointersSupplier;
import net.kyori.adventure.util.TriState;
import net.md_5.bungee.api.chat.BaseComponent;
Expand All @@ -69,13 +72,15 @@
import net.minecraft.network.protocol.game.ClientboundBlockDestructionPacket;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundBundlePacket;
import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket;
import net.minecraft.network.protocol.game.ClientboundCustomChatCompletionsPacket;
import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
import net.minecraft.network.protocol.game.ClientboundHurtAnimationPacket;
import net.minecraft.network.protocol.game.ClientboundLevelEventPacket;
import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket;
import net.minecraft.network.protocol.game.ClientboundMapItemDataPacket;
import net.minecraft.network.protocol.game.ClientboundOpenBookPacket;
import net.minecraft.network.protocol.game.ClientboundOpenSignEditorPacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
Expand All @@ -90,6 +95,7 @@
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket;
import net.minecraft.network.protocol.game.ClientboundSetHealthPacket;
import net.minecraft.network.protocol.game.ClientboundSetPlayerInventoryPacket;
import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket;
import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket;
import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket;
Expand All @@ -108,6 +114,7 @@
import net.minecraft.server.players.UserWhiteListEntry;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
Expand Down Expand Up @@ -202,6 +209,7 @@
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.InventoryView.Property;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.ItemType;
import org.bukkit.map.MapCursor;
import org.bukkit.map.MapView;
import org.bukkit.metadata.MetadataValue;
Expand Down Expand Up @@ -2824,17 +2832,6 @@ public void updateCommands() {
this.server.getServer().getCommands().sendCommands(this.getHandle());
}

@Override
public void openBook(ItemStack book) {
Preconditions.checkArgument(book != null, "ItemStack cannot be null");
Preconditions.checkArgument(book.getType() == Material.WRITTEN_BOOK, "ItemStack Material (%s) must be Material.WRITTEN_BOOK", book.getType());

ItemStack hand = this.getInventory().getItemInMainHand();
this.getInventory().setItemInMainHand(book);
this.getHandle().openItemGui(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(book), net.minecraft.world.InteractionHand.MAIN_HAND);
this.getInventory().setItemInMainHand(hand);
}
Comment thread
Doc94 marked this conversation as resolved.

@Override
public void openSign(@NonNull Sign sign, @NonNull Side side) {
CraftSign.openSign(sign, this, side);
Expand Down Expand Up @@ -3073,17 +3070,30 @@ public void stopSound(final net.kyori.adventure.sound.SoundStop stop) {
}

@Override
public void openBook(final net.kyori.adventure.inventory.Book book) {
final java.util.Locale locale = this.getHandle().adventure$locale;
final net.minecraft.world.item.ItemStack item = io.papermc.paper.adventure.PaperAdventure.asItemStack(book, locale);
final ServerPlayer player = this.getHandle();
final ServerGamePacketListenerImpl connection = player.connection;
final net.minecraft.world.entity.player.Inventory inventory = player.getInventory();
final int slot = inventory.getNonEquipmentItems().size() + inventory.getSelectedSlot();
final int stateId = getHandle().containerMenu.getStateId();
connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(0, stateId, slot, item));
connection.send(new net.minecraft.network.protocol.game.ClientboundOpenBookPacket(net.minecraft.world.InteractionHand.MAIN_HAND));
connection.send(new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(0, stateId, slot, inventory.getSelectedItem()));
public void openBook(ItemStack book) {
Preconditions.checkArgument(book != null, "ItemStack cannot be null");
Preconditions.checkArgument(book.hasData(DataComponentTypes.WRITTEN_BOOK_CONTENT), "ItemStack must have a 'written_book_content' component");

final ItemStack previousItem = this.getInventory().getItemInMainHand();
this.getInventory().setItemInMainHand(book);
this.getHandle().openItemGui(CraftItemStack.asNMSCopy(book), InteractionHand.MAIN_HAND);
this.getInventory().setItemInMainHand(previousItem);
}

@Override
public void openBook(final Book book) {
final ItemStack mutatedItem = ItemType.WRITTEN_BOOK.createItemStack(); // dummy item
mutatedItem.setData(DataComponentTypes.WRITTEN_BOOK_CONTENT, WrittenBookContent.writtenBookContent("", "").addPages(book.pages()));

final net.minecraft.world.item.ItemStack selectedItem = this.getHandle().getInventory().getSelectedItem();
final int slot = this.getHandle().getInventory().getSelectedSlot();
this.getHandle().connection.send(new ClientboundBundlePacket(
List.of(
new ClientboundSetPlayerInventoryPacket(slot, CraftItemStack.unwrap(mutatedItem)),
new ClientboundOpenBookPacket(InteractionHand.MAIN_HAND),
new ClientboundSetPlayerInventoryPacket(slot, selectedItem)
)
));
}

@Override
Expand Down
Loading