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 }