Repository: PaperMC/Paper
File: paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java (Java)

Code before:

    @Override
    public void playSound(final net.kyori.adventure.sound.Sound sound, final net.kyori.adventure.sound.Sound.Emitter emitter) {
        final Entity entity;
        if (emitter == net.kyori.adventure.sound.Sound.Emitter.self()) {
            entity = this.getHandle();
        } else if (emitter instanceof CraftEntity craftEntity) {
            entity = craftEntity.getHandle();
        } else {
            throw new IllegalArgumentException("Sound emitter must be an Entity or self(), but was: " + emitter);
        }
        this.getHandle().connection.send(io.papermc.paper.adventure.PaperAdventure.asSoundPacket(sound, entity, sound.seed().orElseGet(this.getHandle().getRandom()::nextLong), null));
    }

    @Override
    public void stopSound(final net.kyori.adventure.sound.SoundStop stop) {
        this.getHandle().connection.send(new ClientboundStopSoundPacket(
            io.papermc.paper.adventure.PaperAdventure.asVanillaNullable(stop.sound()),
            io.papermc.paper.adventure.PaperAdventure.asVanillaNullable(stop.source())
        ));
    }

    @Override
    public void openBook(ItemStack book) {
        Preconditions.checkArgument(book != null, "ItemStack cannot be null");
        Preconditions.checkArgument(book.hasData(DataComponentTypes.WRITTEN_BOOK_CONTENT), "ItemStack Material (%s) must have a WrittenBookContent Component", 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);
    }

    @Override
    public void openBook(final net.kyori.adventure.inventory.Book book) {
        ItemStack mutatedItem = ItemType.WRITTEN_BOOK.createItemStack(); // dummy item for set the data
        mutatedItem.setData(DataComponentTypes.WRITTEN_BOOK_CONTENT, io.papermc.paper.datacomponent.item.WrittenBookContent.writtenBookContent("", "").addPages(book.pages()).build());

        final net.minecraft.world.item.ItemStack selectedItem = this.getHandle().getInventory().getSelectedItem();
        final int slot = this.getHandle().getInventory().getNonEquipmentItems().size() + this.getHandle().getInventory().getSelectedSlot();
        final int stateId = getHandle().containerMenu.getStateId();
        this.getHandle().connection.send(new ClientboundBundlePacket(
            List.of(
                new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(0, stateId, slot, CraftItemStack.unwrap(mutatedItem)),
                new net.minecraft.network.protocol.game.ClientboundOpenBookPacket(net.minecraft.world.InteractionHand.MAIN_HAND),
                new net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket(0, stateId, slot, selectedItem)
            )
        ));
    }

    @Override

Review comment (suggestion):
This message is not accurate it's not the material that should have the component but the item stack alone.
You can import types in this class too no need to keep FQN around.

Code after:
    @Override
    public void setWardenWarningLevel(int warningLevel) {
        this.getHandle().wardenSpawnTracker.setWarningLevel(warningLevel);
    }

    @Override
    public void increaseWardenWarningLevel() {
        this.getHandle().wardenSpawnTracker.increaseWarningLevel();
    }
    // Paper end

    // Paper start
    @Override
    public Duration getIdleDuration() {
        return Duration.ofMillis(net.minecraft.Util.getMillis() - this.getHandle().getLastActionTime());
    }

    @Override
    public void resetIdleDuration() {
        this.getHandle().resetLastActionTime();
    }
    // Paper end

    // Paper start - Add chunk view API
    @Override
    public Set<java.lang.Long> getSentChunkKeys() {
        org.spigotmc.AsyncCatcher.catchOp("accessing sent chunks");
        return FeatureHooks.getSentChunkKeys(this.getHandle());
    }

    @Override
    public Set<org.bukkit.Chunk> getSentChunks() {
        org.spigotmc.AsyncCatcher.catchOp("accessing sent chunks");
        return FeatureHooks.getSentChunks(this.getHandle());
    }

    @Override
    public boolean isChunkSent(final long chunkKey) {
        org.spigotmc.AsyncCatcher.catchOp("accessing sent chunks");
        return FeatureHooks.isChunkSent(this.getHandle(), chunkKey);
    }
    // Paper end

    public Player.Spigot spigot() {
        return this.spigot;
    }
    // Spigot end

    @Override
    public int getViewDistance() {
        return ca.spottedleaf.moonrise.common.PlatformHooks.get().getViewDistance(this.getHandle());