up3
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
package block
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"github.com/df-mc/dragonfly/server/block/model"
|
||||
"github.com/df-mc/dragonfly/server/internal/nbtconv"
|
||||
"github.com/df-mc/dragonfly/server/item"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"github.com/df-mc/dragonfly/server/world/sound"
|
||||
"github.com/go-gl/mathgl/mgl64"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Lectern is a librarian's job site block found in villages. It is used to hold books for multiple players to read in
|
||||
// multiplayer.
|
||||
// TODO: Redstone functionality.
|
||||
type Lectern struct {
|
||||
bass
|
||||
sourceWaterDisplacer
|
||||
|
||||
// Facing represents the direction the Lectern is facing.
|
||||
Facing cube.Direction
|
||||
// Book is the book currently held by the Lectern.
|
||||
Book item.Stack
|
||||
// Page is the page the Lectern is currently on in the book.
|
||||
Page int
|
||||
}
|
||||
|
||||
// Model ...
|
||||
func (Lectern) Model() world.BlockModel {
|
||||
return model.Lectern{}
|
||||
}
|
||||
|
||||
// FuelInfo ...
|
||||
func (Lectern) FuelInfo() item.FuelInfo {
|
||||
return newFuelInfo(time.Second * 15)
|
||||
}
|
||||
|
||||
// SideClosed ...
|
||||
func (Lectern) SideClosed(cube.Pos, cube.Pos, *world.Tx) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// BreakInfo ...
|
||||
func (l Lectern) BreakInfo() BreakInfo {
|
||||
d := []item.Stack{item.NewStack(Lectern{}, 1)}
|
||||
if !l.Book.Empty() {
|
||||
d = append(d, l.Book)
|
||||
}
|
||||
return newBreakInfo(2.5, alwaysHarvestable, axeEffective, simpleDrops(d...))
|
||||
}
|
||||
|
||||
// UseOnBlock ...
|
||||
func (l Lectern) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, tx *world.Tx, user item.User, ctx *item.UseContext) (used bool) {
|
||||
pos, _, used = firstReplaceable(tx, pos, face, l)
|
||||
if !used {
|
||||
return false
|
||||
}
|
||||
l.Facing = user.Rotation().Direction().Opposite()
|
||||
place(tx, pos, l, user, ctx)
|
||||
return placed(ctx)
|
||||
}
|
||||
|
||||
// readableBook represents a book that can be read through a lectern.
|
||||
type readableBook interface {
|
||||
// TotalPages returns the total number of pages in the book.
|
||||
TotalPages() int
|
||||
// Page returns a specific page from the book and true when the page exists. It will otherwise return an empty string
|
||||
// and false.
|
||||
Page(page int) (string, bool)
|
||||
}
|
||||
|
||||
// Activate ...
|
||||
func (l Lectern) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, u item.User, ctx *item.UseContext) bool {
|
||||
if !l.Book.Empty() {
|
||||
if opener, ok := u.(ContainerOpener); ok {
|
||||
opener.OpenBlockContainer(pos, tx)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
held, _ := u.HeldItems()
|
||||
if _, ok := held.Item().(readableBook); !ok {
|
||||
// We can't put a non-book item on the lectern.
|
||||
return false
|
||||
}
|
||||
|
||||
l.Book, l.Page = held, 0
|
||||
tx.SetBlock(pos, l, nil)
|
||||
|
||||
tx.PlaySound(pos.Vec3Centre(), sound.LecternBookPlace{})
|
||||
ctx.SubtractFromCount(1)
|
||||
return true
|
||||
}
|
||||
|
||||
// Punch ...
|
||||
func (l Lectern) Punch(pos cube.Pos, _ cube.Face, tx *world.Tx, _ item.User) {
|
||||
if l.Book.Empty() {
|
||||
// We can't remove a book from the lectern if there isn't one.
|
||||
return
|
||||
}
|
||||
|
||||
dropItem(tx, l.Book, pos.Side(cube.FaceUp).Vec3Middle())
|
||||
|
||||
l.Book = item.Stack{}
|
||||
tx.SetBlock(pos, l, nil)
|
||||
tx.PlaySound(pos.Vec3Centre(), sound.Attack{})
|
||||
}
|
||||
|
||||
// TurnPage updates the page the lectern is currently on to the page given.
|
||||
func (l Lectern) TurnPage(pos cube.Pos, tx *world.Tx, page int) error {
|
||||
if page == l.Page {
|
||||
// We're already on the correct page, so we don't need to do anything.
|
||||
return nil
|
||||
}
|
||||
if l.Book.Empty() {
|
||||
return fmt.Errorf("lectern at %v is empty", pos)
|
||||
}
|
||||
if r, ok := l.Book.Item().(readableBook); ok && (page >= r.TotalPages() || page < 0) {
|
||||
return fmt.Errorf("page number %d is out of bounds", page)
|
||||
}
|
||||
l.Page = page
|
||||
tx.SetBlock(pos, l, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeNBT ...
|
||||
func (l Lectern) EncodeNBT() map[string]any {
|
||||
m := map[string]any{
|
||||
"hasBook": boolByte(!l.Book.Empty()),
|
||||
"page": int32(l.Page),
|
||||
"id": "Lectern",
|
||||
}
|
||||
if r, ok := l.Book.Item().(readableBook); ok {
|
||||
m["book"] = nbtconv.WriteItem(l.Book, true)
|
||||
m["totalPages"] = int32(r.TotalPages())
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// DecodeNBT ...
|
||||
func (l Lectern) DecodeNBT(m map[string]any) any {
|
||||
l.Page = int(nbtconv.Int32(m, "page"))
|
||||
l.Book = nbtconv.MapItem(m, "book")
|
||||
return l
|
||||
}
|
||||
|
||||
// EncodeItem ...
|
||||
func (Lectern) EncodeItem() (name string, meta int16) {
|
||||
return "minecraft:lectern", 0
|
||||
}
|
||||
|
||||
// EncodeBlock ...
|
||||
func (l Lectern) EncodeBlock() (string, map[string]any) {
|
||||
return "minecraft:lectern", map[string]any{
|
||||
"minecraft:cardinal_direction": l.Facing.String(),
|
||||
"powered_bit": uint8(0), // We don't support redstone, anyway.
|
||||
}
|
||||
}
|
||||
|
||||
// allLecterns ...
|
||||
func allLecterns() (lecterns []world.Block) {
|
||||
for _, f := range cube.Directions() {
|
||||
lecterns = append(lecterns, Lectern{Facing: f})
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user