138 lines
3.8 KiB
Go
138 lines
3.8 KiB
Go
|
|
package block
|
||
|
|
|
||
|
|
import (
|
||
|
|
"github.com/df-mc/dragonfly/server/block/cube"
|
||
|
|
"github.com/df-mc/dragonfly/server/internal/nbtconv"
|
||
|
|
"github.com/df-mc/dragonfly/server/item"
|
||
|
|
"github.com/df-mc/dragonfly/server/world"
|
||
|
|
"github.com/go-gl/mathgl/mgl64"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Banner is a tall decorative block that can be customised.
|
||
|
|
type Banner struct {
|
||
|
|
empty
|
||
|
|
transparent
|
||
|
|
|
||
|
|
// Colour is the colour of the banner.
|
||
|
|
Colour item.Colour
|
||
|
|
// Attach is the attachment of the Banner. It is either of the type WallAttachment or StandingAttachment.
|
||
|
|
Attach Attachment
|
||
|
|
// Patterns represents the patterns the Banner should show when rendering.
|
||
|
|
Patterns []BannerPatternLayer
|
||
|
|
// Illager returns true if the banner is an illager banner.
|
||
|
|
Illager bool
|
||
|
|
}
|
||
|
|
|
||
|
|
// Pick ...
|
||
|
|
func (b Banner) Pick() item.Stack {
|
||
|
|
return item.NewStack(Banner{Colour: b.Colour, Patterns: b.Patterns, Illager: b.Illager}, 1)
|
||
|
|
}
|
||
|
|
|
||
|
|
// MaxCount ...
|
||
|
|
func (Banner) MaxCount() int {
|
||
|
|
return 16
|
||
|
|
}
|
||
|
|
|
||
|
|
// BreakInfo ...
|
||
|
|
func (b Banner) BreakInfo() BreakInfo {
|
||
|
|
return newBreakInfo(1, alwaysHarvestable, axeEffective, oneOf(b))
|
||
|
|
}
|
||
|
|
|
||
|
|
// FuelInfo ...
|
||
|
|
func (Banner) FuelInfo() item.FuelInfo {
|
||
|
|
return newFuelInfo(time.Second * 15)
|
||
|
|
}
|
||
|
|
|
||
|
|
// UseOnBlock ...
|
||
|
|
func (b Banner) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, tx *world.Tx, user item.User, ctx *item.UseContext) (used bool) {
|
||
|
|
pos, face, used = firstReplaceable(tx, pos, face, b)
|
||
|
|
if !used || face == cube.FaceDown {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
if face == cube.FaceUp {
|
||
|
|
b.Attach = StandingAttachment(user.Rotation().Orientation().Opposite())
|
||
|
|
place(tx, pos, b, user, ctx)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
b.Attach = WallAttachment(face.Direction())
|
||
|
|
place(tx, pos, b, user, ctx)
|
||
|
|
return placed(ctx)
|
||
|
|
}
|
||
|
|
|
||
|
|
// NeighbourUpdateTick ...
|
||
|
|
func (b Banner) NeighbourUpdateTick(pos, _ cube.Pos, tx *world.Tx) {
|
||
|
|
if b.Attach.hanging {
|
||
|
|
if _, ok := tx.Block(pos.Side(b.Attach.facing.Opposite().Face())).(Air); ok {
|
||
|
|
breakBlock(b, pos, tx)
|
||
|
|
}
|
||
|
|
} else if _, ok := tx.Block(pos.Side(cube.FaceDown)).(Air); ok {
|
||
|
|
breakBlock(b, pos, tx)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// EncodeItem ...
|
||
|
|
func (b Banner) EncodeItem() (name string, meta int16) {
|
||
|
|
return "minecraft:banner", invertColour(b.Colour)
|
||
|
|
}
|
||
|
|
|
||
|
|
// EncodeBlock ...
|
||
|
|
func (b Banner) EncodeBlock() (name string, properties map[string]any) {
|
||
|
|
if b.Attach.hanging {
|
||
|
|
return "minecraft:wall_banner", map[string]any{"facing_direction": int32(b.Attach.facing + 2)}
|
||
|
|
}
|
||
|
|
return "minecraft:standing_banner", map[string]any{"ground_sign_direction": int32(b.Attach.o)}
|
||
|
|
}
|
||
|
|
|
||
|
|
// EncodeNBT ...
|
||
|
|
func (b Banner) EncodeNBT() map[string]any {
|
||
|
|
patterns := make([]any, 0, len(b.Patterns))
|
||
|
|
for _, p := range b.Patterns {
|
||
|
|
patterns = append(patterns, p.EncodeNBT())
|
||
|
|
}
|
||
|
|
return map[string]any{
|
||
|
|
"id": "Banner",
|
||
|
|
"Patterns": patterns,
|
||
|
|
"Type": int32(boolByte(b.Illager)),
|
||
|
|
"Base": int32(invertColour(b.Colour)),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// DecodeNBT ...
|
||
|
|
func (b Banner) DecodeNBT(m map[string]any) any {
|
||
|
|
if _, ok := m["Base"]; ok {
|
||
|
|
// Banner items do not have the Base NBT.
|
||
|
|
b.Colour = invertColourID(int16(nbtconv.Int32(m, "Base")))
|
||
|
|
}
|
||
|
|
b.Illager = nbtconv.Int32(m, "Type") == 1
|
||
|
|
if patterns := nbtconv.Slice(m, "Patterns"); patterns != nil {
|
||
|
|
b.Patterns = make([]BannerPatternLayer, len(patterns))
|
||
|
|
for i, p := range b.Patterns {
|
||
|
|
b.Patterns[i] = p.DecodeNBT(patterns[i].(map[string]any)).(BannerPatternLayer)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return b
|
||
|
|
}
|
||
|
|
|
||
|
|
// invertColour converts the item.Colour passed and returns the colour ID inverted.
|
||
|
|
func invertColour(c item.Colour) int16 {
|
||
|
|
return ^int16(c.Uint8()) & 0xf
|
||
|
|
}
|
||
|
|
|
||
|
|
// invertColourID converts the int16 passed the returns the item.Colour inverted.
|
||
|
|
func invertColourID(id int16) item.Colour {
|
||
|
|
return item.Colours()[uint8(^id&0xf)]
|
||
|
|
}
|
||
|
|
|
||
|
|
// allBanners returns all possible banners.
|
||
|
|
func allBanners() (banners []world.Block) {
|
||
|
|
for _, d := range cube.Directions() {
|
||
|
|
banners = append(banners, Banner{Attach: WallAttachment(d)})
|
||
|
|
}
|
||
|
|
for o := cube.Orientation(0); o <= 15; o++ {
|
||
|
|
banners = append(banners, Banner{Attach: StandingAttachment(o)})
|
||
|
|
}
|
||
|
|
return
|
||
|
|
}
|