github.com/df-mc/dragonfly@v0.9.13/server/block/kelp.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/go-gl/mathgl/mgl64" 8 "math/rand" 9 ) 10 11 // Kelp is an underwater block which can grow on top of solids underwater. 12 type Kelp struct { 13 empty 14 transparent 15 sourceWaterDisplacer 16 17 // Age is the age of the kelp block which can be 0-25. If age is 25, kelp won't grow any further. 18 Age int 19 } 20 21 // SmeltInfo ... 22 func (k Kelp) SmeltInfo() item.SmeltInfo { 23 return newFoodSmeltInfo(item.NewStack(item.DriedKelp{}, 1), 0.1) 24 } 25 26 // BoneMeal ... 27 func (k Kelp) BoneMeal(pos cube.Pos, w *world.World) bool { 28 for y := pos.Y(); y <= w.Range()[1]; y++ { 29 currentPos := cube.Pos{pos.X(), y, pos.Z()} 30 block := w.Block(currentPos) 31 if kelp, ok := block.(Kelp); ok { 32 if kelp.Age == 25 { 33 break 34 } 35 continue 36 } 37 if water, ok := block.(Water); ok && water.Depth == 8 { 38 w.SetBlock(currentPos, Kelp{Age: k.Age + 1}, nil) 39 return true 40 } 41 break 42 } 43 return false 44 } 45 46 // BreakInfo ... 47 func (k Kelp) BreakInfo() BreakInfo { 48 return newBreakInfo(0, alwaysHarvestable, nothingEffective, oneOf(k)) 49 } 50 51 // CompostChance ... 52 func (Kelp) CompostChance() float64 { 53 return 0.3 54 } 55 56 // EncodeItem ... 57 func (Kelp) EncodeItem() (name string, meta int16) { 58 return "minecraft:kelp", 0 59 } 60 61 // EncodeBlock ... 62 func (k Kelp) EncodeBlock() (name string, properties map[string]any) { 63 return "minecraft:kelp", map[string]any{"kelp_age": int32(k.Age)} 64 } 65 66 // SideClosed will always return false since kelp doesn't close any side. 67 func (Kelp) SideClosed(cube.Pos, cube.Pos, *world.World) bool { 68 return false 69 } 70 71 // withRandomAge returns a new Kelp block with its age value randomized between 0 and 24. 72 func (k Kelp) withRandomAge() Kelp { 73 k.Age = rand.Intn(25) 74 return k 75 } 76 77 // UseOnBlock ... 78 func (k Kelp) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) (used bool) { 79 pos, _, used = firstReplaceable(w, pos, face, k) 80 if !used { 81 return 82 } 83 84 below := pos.Side(cube.FaceDown) 85 belowBlock := w.Block(below) 86 if _, kelp := belowBlock.(Kelp); !kelp { 87 if !belowBlock.Model().FaceSolid(below, cube.FaceUp, w) { 88 return false 89 } 90 } 91 92 liquid, ok := w.Liquid(pos) 93 if !ok { 94 return false 95 } else if _, ok := liquid.(Water); !ok || liquid.LiquidDepth() < 8 { 96 return false 97 } 98 99 // When first placed, kelp gets a random age between 0 and 24. 100 place(w, pos, k.withRandomAge(), user, ctx) 101 return placed(ctx) 102 } 103 104 // NeighbourUpdateTick ... 105 func (k Kelp) NeighbourUpdateTick(pos, changed cube.Pos, w *world.World) { 106 if _, ok := w.Liquid(pos); !ok { 107 w.SetBlock(pos, nil, nil) 108 return 109 } 110 if changed.Y()-1 == pos.Y() { 111 // When a kelp block is broken above, the kelp block underneath it gets a new random age. 112 w.SetBlock(pos, k.withRandomAge(), nil) 113 } 114 115 below := pos.Side(cube.FaceDown) 116 belowBlock := w.Block(below) 117 if _, kelp := belowBlock.(Kelp); !kelp { 118 if !belowBlock.Model().FaceSolid(below, cube.FaceUp, w) { 119 w.SetBlock(pos, nil, nil) 120 } 121 } 122 } 123 124 // RandomTick ... 125 func (k Kelp) RandomTick(pos cube.Pos, w *world.World, r *rand.Rand) { 126 // Every random tick, there's a 14% chance for Kelp to grow if its age is below 25. 127 if r.Intn(100) < 15 && k.Age < 25 { 128 abovePos := pos.Side(cube.FaceUp) 129 130 liquid, ok := w.Liquid(abovePos) 131 132 // For kelp to grow, there must be only water above. 133 if !ok { 134 return 135 } else if _, ok := liquid.(Water); ok { 136 switch w.Block(abovePos).(type) { 137 case Air, Water: 138 w.SetBlock(abovePos, Kelp{Age: k.Age + 1}, nil) 139 if liquid.LiquidDepth() < 8 { 140 // When kelp grows into a water block, the water block becomes a source block. 141 w.SetLiquid(abovePos, Water{Still: true, Depth: 8, Falling: false}) 142 } 143 } 144 } 145 } 146 } 147 148 // allKelp returns all possible states of a kelp block. 149 func allKelp() (b []world.Block) { 150 for i := 0; i < 26; i++ { 151 b = append(b, Kelp{Age: i}) 152 } 153 return 154 }