plushmonkey / mclib

C++ library for connecting to Minecraft servers
MIT License
80 stars 17 forks source link

Help with getting text from book using nbt data #19

Closed unlimitedcoder2 closed 5 years ago

unlimitedcoder2 commented 5 years ago

I was wondering if it was possible to get this text Image . I currently have the code

mc::nbt::TagCompound bookRoot = m_Client->GetInventoryManager()->GetPlayerInventory()->GetCursorItem().GetNBT().GetRoot();
mc::nbt::TagList* pagesList = bookRoot.GetTag<mc::nbt::TagList>(L"pages");
std::vector<mc::nbt::TagPtr> pages = pagesList->GetList();
mc::nbt::TagPtr page = pages[0];

and was wondering if you could point me into the right direction so that I can get all the data listed in this link

plushmonkey commented 5 years ago

Yeah, here's an example class that will read the book pages. The NBT api is pretty weak because I just added it on real quick to get access. There's an issue with the list type where it's not properly serializing, but I just pushed a commit that should fix that.

class BookReader : public mc::protocol::packets::PacketHandler {
public:
    BookReader(mc::protocol::packets::PacketDispatcher* dispatcher, mc::core::Client& client, s32 written_book_id) 
        : mc::protocol::packets::PacketHandler(dispatcher), 
          client_(client),
          written_book_id_(written_book_id)
    {
        GetDispatcher()->RegisterHandler(mc::protocol::State::Play, mc::protocol::play::Chat, this);
    }

    ~BookReader() {
        GetDispatcher()->UnregisterHandler(this);
    }

    void HandlePacket(mc::protocol::packets::in::ChatPacket* packet) {
        std::string message = mc::util::ParseChatNode(packet->GetChatData());

        if (message.find("!book") != std::string::npos) {
            std::cout << "Looking for written book." << std::endl;

            s32 book_slot = client_.GetInventoryManager()->GetPlayerInventory()->FindItemById(written_book_id_);

            if (book_slot != -1) {
                std::cout << "Found written book in slot " << book_slot << std::endl;
                auto book = client_.GetInventoryManager()->GetPlayerInventory()->GetItem(book_slot);
                bool has_nbt = book.GetNBT().HasData();

                if (has_nbt) {
                    auto& nbt = book.GetNBT().GetRoot();

                    auto author = nbt.GetTag<mc::nbt::TagString>(L"author");
                    if (author != nullptr) {
                        std::wcout << L"Author: " << author->GetValue() << std::endl;
                    }

                    auto title = nbt.GetTag<mc::nbt::TagString>(L"title");
                    if (title != nullptr) {
                        std::wcout << L"Title: " << title->GetValue() << std::endl;
                    }

                    auto pages = nbt.GetTag<mc::nbt::TagList>(L"pages");
                    for (auto page : pages->GetList()) {
                        assert(page->GetType() == mc::nbt::TagType::String);

                        auto text_node = (mc::nbt::TagString*)page.get();

                        std::wcout << text_node->GetValue() << std::endl;
                    }
                }
            } else {
                std::cout << "No written book found in inventory." << std::endl;
            }
        }
    }

private:
    mc::core::Client& client_;
    s32 written_book_id_;
};
unlimitedcoder2 commented 5 years ago

Thank you for responding so quickly and for helping me resolve the issue!