github.com/df-mc/dragonfly@v0.9.13/server/block/cactus.go (about) 1 package block 2 3 import ( 4 "github.com/df-mc/dragonfly/server/block/cube" 5 "github.com/df-mc/dragonfly/server/block/model" 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 "math/rand" 11 ) 12 13 // Cactus is a plant block that generates naturally in dry areas and causes damage. 14 type Cactus struct { 15 transparent 16 17 // Age is the growth state of cactus. Values range from 0 to 15. 18 Age int 19 } 20 21 // UseOnBlock handles making sure the neighbouring blocks are air. 22 func (c Cactus) 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 Cactus) 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 Cactus) RandomTick(pos cube.Pos, w *world.World, _ *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}), Cactus{Age: 0}, nil) 54 break 55 } else if _, ok := w.Block(pos.Add(cube.Pos{0, y})).(Cactus); !ok { 56 break 57 } 58 } 59 } 60 } 61 w.SetBlock(pos, c, nil) 62 } 63 64 // canGrowHere implements logic to check if cactus can live/grow here. 65 func (c Cactus) canGrowHere(pos cube.Pos, w *world.World, recursive bool) bool { 66 for _, face := range cube.HorizontalFaces() { 67 if _, ok := w.Block(pos.Side(face)).(Air); !ok { 68 return false 69 } 70 } 71 if _, ok := w.Block(pos.Side(cube.FaceDown)).(Cactus); ok && recursive { 72 return c.canGrowHere(pos.Side(cube.FaceDown), w, recursive) 73 } 74 return supportsVegetation(c, w.Block(pos.Sub(cube.Pos{0, 1}))) 75 } 76 77 // EntityInside ... 78 func (c Cactus) EntityInside(_ cube.Pos, _ *world.World, e world.Entity) { 79 if l, ok := e.(livingEntity); ok && !l.AttackImmune() { 80 l.Hurt(0.5, DamageSource{Block: c}) 81 } 82 } 83 84 // BreakInfo ... 85 func (c Cactus) BreakInfo() BreakInfo { 86 return newBreakInfo(0.4, alwaysHarvestable, nothingEffective, oneOf(c)) 87 } 88 89 // CompostChance ... 90 func (Cactus) CompostChance() float64 { 91 return 0.5 92 } 93 94 // EncodeItem ... 95 func (c Cactus) EncodeItem() (name string, meta int16) { 96 return "minecraft:cactus", 0 97 } 98 99 // EncodeBlock ... 100 func (c Cactus) EncodeBlock() (name string, properties map[string]any) { 101 return "minecraft:cactus", map[string]any{"age": int32(c.Age)} 102 } 103 104 // Model ... 105 func (c Cactus) Model() world.BlockModel { 106 return model.Cactus{} 107 } 108 109 // allCactus returns all possible states of a cactus block. 110 func allCactus() (b []world.Block) { 111 for i := 0; i < 16; i++ { 112 b = append(b, Cactus{Age: i}) 113 } 114 return 115 } 116 117 // DamageSource is passed as world.DamageSource for damage caused by a block, 118 // such as a cactus or a falling anvil. 119 type DamageSource struct { 120 // Block is the block that caused the damage. 121 Block world.Block 122 } 123 124 func (DamageSource) ReducedByResistance() bool { return true } 125 func (DamageSource) ReducedByArmour() bool { return true } 126 func (DamageSource) Fire() bool { return false }