github.com/df-mc/dragonfly@v0.9.13/server/block/sugar_cane.go (about) 1 package block 2 3 import ( 4 "github.com/df-mc/dragonfly/server/block/cube" 5 "github.com/df-mc/dragonfly/server/item" 6 "github.com/df-mc/dragonfly/server/world" 7 "github.com/df-mc/dragonfly/server/world/particle" 8 "github.com/go-gl/mathgl/mgl64" 9 "math/rand" 10 ) 11 12 // SugarCane is a plant block that generates naturally near water. 13 type SugarCane struct { 14 empty 15 transparent 16 17 // Age is the growth state of sugar cane. Values range from 0 to 15. 18 Age int 19 } 20 21 // UseOnBlock ensures the placement of the block is OK. 22 func (c SugarCane) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) (used bool) { 23 pos, _, used = firstReplaceable(w, pos, face, c) 24 if !used { 25 return false 26 } 27 if !c.canGrowHere(pos, w, true) { 28 return false 29 } 30 31 place(w, pos, c, user, ctx) 32 return placed(ctx) 33 } 34 35 // NeighbourUpdateTick ... 36 func (c SugarCane) NeighbourUpdateTick(pos, _ cube.Pos, w *world.World) { 37 if !c.canGrowHere(pos, w, true) { 38 w.SetBlock(pos, nil, nil) 39 w.AddParticle(pos.Vec3Centre(), particle.BlockBreak{Block: c}) 40 dropItem(w, item.NewStack(c, 1), pos.Vec3Centre()) 41 } 42 } 43 44 // RandomTick ... 45 func (c SugarCane) RandomTick(pos cube.Pos, w *world.World, r *rand.Rand) { 46 if c.Age < 15 { 47 c.Age++ 48 } else if c.Age == 15 { 49 c.Age = 0 50 if c.canGrowHere(pos.Side(cube.FaceDown), w, false) { 51 for y := 1; y < 3; y++ { 52 if _, ok := w.Block(pos.Add(cube.Pos{0, y})).(Air); ok { 53 w.SetBlock(pos.Add(cube.Pos{0, y}), SugarCane{}, nil) 54 break 55 } else if _, ok := w.Block(pos.Add(cube.Pos{0, y})).(SugarCane); !ok { 56 break 57 } 58 } 59 } 60 } 61 w.SetBlock(pos, c, nil) 62 } 63 64 // BoneMeal ... 65 func (c SugarCane) BoneMeal(pos cube.Pos, w *world.World) bool { 66 for _, ok := w.Block(pos.Side(cube.FaceDown)).(SugarCane); ok; _, ok = w.Block(pos.Side(cube.FaceDown)).(SugarCane) { 67 pos = pos.Side(cube.FaceDown) 68 } 69 if c.canGrowHere(pos.Side(cube.FaceDown), w, false) { 70 for y := 1; y < 3; y++ { 71 if _, ok := w.Block(pos.Add(cube.Pos{0, y})).(Air); ok { 72 w.SetBlock(pos.Add(cube.Pos{0, y}), SugarCane{}, nil) 73 } 74 } 75 return true 76 } 77 return false 78 } 79 80 // canGrowHere implements logic to check if sugar cane can live/grow here. 81 func (c SugarCane) canGrowHere(pos cube.Pos, w *world.World, recursive bool) bool { 82 if _, ok := w.Block(pos.Side(cube.FaceDown)).(SugarCane); ok && recursive { 83 return c.canGrowHere(pos.Side(cube.FaceDown), w, recursive) 84 } 85 86 if supportsVegetation(c, w.Block(pos.Sub(cube.Pos{0, 1}))) { 87 for _, face := range cube.HorizontalFaces() { 88 if liquid, ok := w.Liquid(pos.Side(face).Side(cube.FaceDown)); ok { 89 if _, ok := liquid.(Water); ok { 90 return true 91 } 92 } 93 } 94 } 95 return false 96 } 97 98 // HasLiquidDrops ... 99 func (c SugarCane) HasLiquidDrops() bool { 100 return true 101 } 102 103 // BreakInfo ... 104 func (c SugarCane) BreakInfo() BreakInfo { 105 return newBreakInfo(0, alwaysHarvestable, nothingEffective, oneOf(c)) 106 } 107 108 // EncodeItem ... 109 func (c SugarCane) EncodeItem() (name string, meta int16) { 110 return "minecraft:sugar_cane", 0 111 } 112 113 // EncodeBlock ... 114 func (c SugarCane) EncodeBlock() (name string, properties map[string]any) { 115 return "minecraft:reeds", map[string]any{"age": int32(c.Age)} 116 } 117 118 // allSugarCane returns all possible states of a sugar cane block. 119 func allSugarCane() (b []world.Block) { 120 for i := 0; i < 16; i++ { 121 b = append(b, SugarCane{Age: i}) 122 } 123 return 124 }