github.com/df-mc/dragonfly@v0.9.13/server/session/handler_book_edit.go (about)

     1  package session
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/df-mc/dragonfly/server/item"
     6  	"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
     7  )
     8  
     9  // BookEditHandler handles the BookEdit packet.
    10  type BookEditHandler struct{}
    11  
    12  // Handle ...
    13  func (b BookEditHandler) Handle(p packet.Packet, s *Session) error {
    14  	pk := p.(*packet.BookEdit)
    15  
    16  	it, err := s.inv.Item(int(pk.InventorySlot))
    17  	if err != nil {
    18  		return fmt.Errorf("invalid inventory slot index %v", pk.InventorySlot)
    19  	}
    20  	book, ok := it.Item().(item.BookAndQuill)
    21  	if !ok {
    22  		return fmt.Errorf("inventory slot %v does not contain a writable book", pk.InventorySlot)
    23  	}
    24  
    25  	page := int(pk.PageNumber)
    26  	if page >= 50 || page < 0 {
    27  		return fmt.Errorf("page number %v is out of bounds", pk.PageNumber)
    28  	}
    29  	if len(pk.Text) > 256 {
    30  		return fmt.Errorf("text can not be longer than 256 bytes")
    31  	}
    32  
    33  	slot := int(pk.InventorySlot)
    34  	switch pk.ActionType {
    35  	case packet.BookActionReplacePage:
    36  		book = book.SetPage(page, pk.Text)
    37  	case packet.BookActionAddPage:
    38  		if len(book.Pages) >= 50 {
    39  			return fmt.Errorf("unable to add page beyond 50")
    40  		}
    41  		if page >= len(book.Pages) && page <= len(book.Pages)+2 {
    42  			book = book.SetPage(page, "")
    43  			break
    44  		}
    45  		if _, ok := book.Page(page); !ok {
    46  			return fmt.Errorf("unable to insert page at %v", pk.PageNumber)
    47  		}
    48  		book = book.InsertPage(page, pk.Text)
    49  	case packet.BookActionDeletePage:
    50  		if _, ok := book.Page(page); !ok {
    51  			// We break here instead of returning an error because the client can be a page or two ahead in the UI then
    52  			// the actual pages representation server side. The client still sends the deletion indexes.
    53  			break
    54  		}
    55  		book = book.DeletePage(page)
    56  	case packet.BookActionSwapPages:
    57  		if pk.SecondaryPageNumber >= 50 {
    58  			return fmt.Errorf("page number out of bounds")
    59  		}
    60  		_, ok := book.Page(page)
    61  		_, ok2 := book.Page(int(pk.SecondaryPageNumber))
    62  		if !ok || !ok2 {
    63  			// We break here instead of returning an error because the client can try to swap pages that don't exist.
    64  			// This happens as a result of the client being a page or two ahead in the UI then the actual pages
    65  			// representation server side. The client still sends the swap indexes.
    66  			break
    67  		}
    68  		book = book.SwapPages(page, int(pk.SecondaryPageNumber))
    69  	case packet.BookActionSign:
    70  		_ = s.inv.SetItem(slot, duplicateStack(it, item.WrittenBook{Title: pk.Title, Author: pk.Author, Pages: book.Pages, Generation: item.OriginalGeneration()}))
    71  		return nil
    72  	}
    73  	_ = s.inv.SetItem(slot, duplicateStack(it, book))
    74  	return nil
    75  }