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

     1  package block
     2  
     3  import (
     4  	"github.com/df-mc/dragonfly/server/block/cube"
     5  	"github.com/df-mc/dragonfly/server/internal/nbtconv"
     6  	"github.com/df-mc/dragonfly/server/item"
     7  	"github.com/df-mc/dragonfly/server/world"
     8  	"github.com/df-mc/dragonfly/server/world/particle"
     9  	"github.com/go-gl/mathgl/mgl64"
    10  	"time"
    11  )
    12  
    13  // Banner is a tall decorative block that can be customized.
    14  type Banner struct {
    15  	empty
    16  	transparent
    17  
    18  	// Colour is the colour of the banner.
    19  	Colour item.Colour
    20  	// Attach is the attachment of the Banner. It is either of the type WallAttachment or StandingAttachment.
    21  	Attach Attachment
    22  	// Patterns represents the patterns the Banner should show when rendering.
    23  	Patterns []BannerPatternLayer
    24  	// Illager returns true if the banner is an illager banner.
    25  	Illager bool
    26  }
    27  
    28  // MaxCount ...
    29  func (Banner) MaxCount() int {
    30  	return 16
    31  }
    32  
    33  // BreakInfo ...
    34  func (b Banner) BreakInfo() BreakInfo {
    35  	return newBreakInfo(1, alwaysHarvestable, axeEffective, oneOf(b))
    36  }
    37  
    38  // FuelInfo ...
    39  func (Banner) FuelInfo() item.FuelInfo {
    40  	return newFuelInfo(time.Second * 15)
    41  }
    42  
    43  // UseOnBlock ...
    44  func (b Banner) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) (used bool) {
    45  	pos, face, used = firstReplaceable(w, pos, face, b)
    46  	if !used || face == cube.FaceDown {
    47  		return false
    48  	}
    49  
    50  	if face == cube.FaceUp {
    51  		b.Attach = StandingAttachment(user.Rotation().Orientation().Opposite())
    52  		place(w, pos, b, user, ctx)
    53  		return
    54  	}
    55  	b.Attach = WallAttachment(face.Direction())
    56  	place(w, pos, b, user, ctx)
    57  	return placed(ctx)
    58  }
    59  
    60  // NeighbourUpdateTick ...
    61  func (b Banner) NeighbourUpdateTick(pos, _ cube.Pos, w *world.World) {
    62  	if b.Attach.hanging {
    63  		if _, ok := w.Block(pos.Side(b.Attach.facing.Opposite().Face())).(Air); ok {
    64  			w.SetBlock(pos, nil, nil)
    65  			w.AddParticle(pos.Vec3Centre(), particle.BlockBreak{Block: b})
    66  			dropItem(w, item.NewStack(b, 1), pos.Vec3Centre())
    67  		}
    68  		return
    69  	}
    70  	if _, ok := w.Block(pos.Side(cube.FaceDown)).(Air); ok {
    71  		w.SetBlock(pos, nil, nil)
    72  		w.AddParticle(pos.Vec3Centre(), particle.BlockBreak{Block: b})
    73  		dropItem(w, item.NewStack(b, 1), pos.Vec3Centre())
    74  	}
    75  }
    76  
    77  // EncodeItem ...
    78  func (b Banner) EncodeItem() (name string, meta int16) {
    79  	return "minecraft:banner", invertColour(b.Colour)
    80  }
    81  
    82  // EncodeBlock ...
    83  func (b Banner) EncodeBlock() (name string, properties map[string]any) {
    84  	if b.Attach.hanging {
    85  		return "minecraft:wall_banner", map[string]any{"facing_direction": int32(b.Attach.facing + 2)}
    86  	}
    87  	return "minecraft:standing_banner", map[string]any{"ground_sign_direction": int32(b.Attach.o)}
    88  }
    89  
    90  // EncodeNBT ...
    91  func (b Banner) EncodeNBT() map[string]any {
    92  	patterns := make([]any, 0, len(b.Patterns))
    93  	for _, p := range b.Patterns {
    94  		patterns = append(patterns, p.EncodeNBT())
    95  	}
    96  	return map[string]any{
    97  		"id":       "Banner",
    98  		"Patterns": patterns,
    99  		"Type":     int32(boolByte(b.Illager)),
   100  		"Base":     int32(invertColour(b.Colour)),
   101  	}
   102  }
   103  
   104  // DecodeNBT ...
   105  func (b Banner) DecodeNBT(m map[string]any) any {
   106  	b.Colour = invertColourID(int16(nbtconv.Int32(m, "Base")))
   107  	b.Illager = nbtconv.Int32(m, "Type") == 1
   108  	if patterns := nbtconv.Slice(m, "Patterns"); patterns != nil {
   109  		b.Patterns = make([]BannerPatternLayer, len(patterns))
   110  		for i, p := range b.Patterns {
   111  			b.Patterns[i] = p.DecodeNBT(patterns[i].(map[string]any)).(BannerPatternLayer)
   112  		}
   113  	}
   114  	return b
   115  }
   116  
   117  // invertColour converts the item.Colour passed and returns the colour ID inverted.
   118  func invertColour(c item.Colour) int16 {
   119  	return ^int16(c.Uint8()) & 0xf
   120  }
   121  
   122  // invertColourID converts the int16 passed the returns the item.Colour inverted.
   123  func invertColourID(id int16) item.Colour {
   124  	return item.Colours()[uint8(^id&0xf)]
   125  }
   126  
   127  // allBanners returns all possible banners.
   128  func allBanners() (banners []world.Block) {
   129  	for _, d := range cube.Directions() {
   130  		banners = append(banners, Banner{Attach: WallAttachment(d)})
   131  	}
   132  	for o := cube.Orientation(0); o <= 15; o++ {
   133  		banners = append(banners, Banner{Attach: StandingAttachment(o)})
   134  	}
   135  	return
   136  }